tohokuaikiのチラシの裏

技術的ネタとか。

PHPでeBayのAPIを使う

結論から言うと、APIのReferenceがあるけどそんなのは見なくてPHPSDKがあるからそれを使ったらすぐだった。

とにかく、SandboxとProductionの両方を行き来するのでどっちがどっちかわからなくなるし、いつの間にかアカウントできてたのでこの2つがリンクするというのはどういう風なんだろう?メールアドレスが同じものをSandboxとProductionの両方で使って登録すればいいのかしら?

わかんなくなったら、My eBayにそれぞれログインする。 * http://my.ebay.com:tilte=Production用 My eBay * Sandbox用 My eBay

eBay developerアカウントを作る

Sandbox用とproduction用の2つ作成。

どちらから作り始めてもいいのだけど、sandbox用は「testuser_」がPrefixになる。

正直、ごちゃごちゃとやってたら2個できたし、その2個がリンクしてるのはどうやって作るのかはわからない。

こっちに書いてあった、テスト用Sandboxユーザーの登録方法

eBay Features - Testing in the Sandbox

  • Set up an email account for each Sandbox test user. A unique email is required for each test user you create.
  • On the eBay Developers Program home page, either create a developer’s account by clicking the Register link or login by clicking the eBay Developer Login button.
  • Sign in as a developer, using your eBay Developers Program username and password.
  • Go to the eBay Sandbox User Registration Tool page.
  • Create your test user by filling in the Username and Password fields. You can leave the other fields as is. Click the Create User button.

アプリケーションを登録してキーを取得

Applicationの名前を決めて、そのキーを取得 f:id:tohokuaiki:20170905183629p:plain

これも、SandboxとProductionの両方。

色々と求められるかもしれないけど、とりあえず携帯電話のSMSがあればなんとか突破できる。

Authトークンを取得

「Auth'n'Aut」と「hOAuth (new security)」と2つあるけど2つとも取得しておく。

f:id:tohokuaiki:20170905183906p:plain

この時、これでもかというくらいにログインをさせられるけど我慢する。

Return URLを登録

Authした時に返却されるURLとかプライバシーポリシーなんかのURLを登録しておく。別にeBayが後でクロールしてチェックとかはしないので適当なURLを入れておけばOK。

f:id:tohokuaiki:20170905184326p:plain

これも、当然SandboxとProductionの両方。

PHP eBay API SDKを取得

素晴らしいサイトから取得する。 devbay.net

面倒なので、githubから直接。
GitHub - davidtsadler/ebay-sdk-examples: Several examples of using the eBay SDK for PHP

composer.jsonがあるので、例によってcomposer installする。

ebay-sdk-examples/configuration.php の設定

大体見ればわかると思う。

ruNameというのが引っかかったのだけど、これは、Return URL Nameということで、先ほど登録してReturn URLの名称なのである。自分の場合、上のキャプチャ画面だとTakashi_ITOH-TakashiI-Junoef-fbnbhijtpとかいうのがそれにあたる。

sellerアカウントを設定

とりあえずこれで使えることは使える。Select系のAPIはProductionを使用する。登録系のAPIはSandboxを使用する。

登録系のAPIを使うにはSellerアカウントにしないといけない。

そのためのセットアップがここにある。Getting started selling on eBay

すると、My eBayのアカウントページで「Seller Account」というのが出てくるらしい。

f:id:tohokuaiki:20170905190806p:plain

で、これを当然のようにSandboxとProductionの両方で行う。

が、SandboxのSellerアカウントが設定できない・・・

上述のは、Productionの設定しか書いてなかった。いや、むしろテストするだけならSandboxの方だけで構わないのに、Productionの方だけSellerアカウントができてしまった。

Sandboxは登録しなくてもSellerテストできるんじゃん?って思ってSDKのサンプル商品登録を試してみたら

Error: You need to create a seller's account.
Before you can list this item we need some additional information to create a seller's account.

って出た。デスヨネー。

仕方ないのでSandboxのMy eBayに行くと How to Sell Items on eBay などと書いてあり、

  • Sign up for PayPal (optional)
  • Fill out the Sell Your Item form

とある。optionalとあるPaypalの方は後回しにして、「go to the Sell Your Item form.」ってリンクをクリックするとリンク切れ。左のメニューにSeller Dashboardというのもあるのでそっちにヒントあるかな?と思ってクリックしたらリンク切れ。切れそう。

My eBay Viewsをシラミ潰す。

とにかくここに「Seller Account」というのが出ればいいのである。

f:id:tohokuaiki:20170905192629p:plain

しかし、PaypalにLinkさせればいいのかと思いきや、昔作って使えてたPaypalのアカウントがペンディングになっててダメだったり、新しくPaypalのSandboxユーザーで作ればいいんじゃないかと

f:id:tohokuaiki:20170906115646p:plain

ここのリンクから作ろうとしたら、PaypalのSandboxユーザー登録で電話番号がアメリカ形式じゃないとかZIPコードがお前の入力した住所と一致してないとかアメリカの電話番号・郵便番号の形式や実在するものを調べて入力したけどダメ。およそSandboxっぽくない。もちろん国をUSから変更することはできない。

困り果ててもう一度検索

もしかすると、作ったSandboxユーザーを「Sellerにする」という発想が間違っているのではないか?・・・すると、こんなページが見つかった。

eBay Features - Testing in the Sandbox

The process of registering a test user is different than that for registering a real user in the Production environment. After you register a Sandbox test user, you can use it to buy and sell test items in the eBay Sandbox.

買う用と売る用の2つのテストアカウントが必要ですよと。

なんだそんなの・・・売る用(Seller)アカウントが作れないから困ってるんだっていうの・・・と思いつつ、この画面のここからもう一つ作ってみる。

f:id:tohokuaiki:20170906120222p:plain

そして、新しいSandboxユーザーでログイン・・・・。

・・・なんかSellerアカウントになってるね。

f:id:tohokuaiki:20170906120524p:plain

で、Tokenを2つ発行して、configuration.phpに設定・・・

vagrant@debian:~/work/ebay/ebay-sdk-examples$ php trading/03-add-auction-item.php
The item was listed to the eBay Sandbox with the Item number 110222380931

おぉっ!!!できてる!!!ホンマ、なんつー、落とし穴やねん。。。

Confluenceのアドオンで別のアドオンのComponentを使う場合の注意

結論から言うと、その別のアドオンを事前にインストールしてないとインストールに失敗しますよということ。

お互いのComponentを循環参照するようなアドオンは作れないってことですね。

こんな簡単なことに気づかずにはまりました。

IDE上ではpom.xml

<dependency>
    <groupId>jp.example.confluence.plugins</groupId>
    <artifactId>foo</artifactId>
    <version>1.00.01</version>
    <scope>system</scope>
    <type>jar</type>
    <systemPath>${basedir}\foo-1.00.01.jar</systemPath>
</dependency>

って記述してたのでIDE自身はjarを見れていたので。

エラーの感じとしては

こんなのが出てた

Caused by: org.osgi.framework.BundleException: Unresolved constraint in bundle jp.example.confluence.plugins.bar [250]: Unable to resolve 250.0: missing requirement [250.0] osgi.wiring.package; (osgi.wiring.package=jp.example.confluence.plugins.foo.component)

まぁ、そりゃそうですよね。

Mediaqueriesの覚え方

いつもこんがらがるので・・・。

min-width

@media only screen and (min-width: 800px) {

「ブラウザが」800px幅が最低でも必要です => 800px以上のブラウザ幅で有効になります。

max-width

@media only screen and (max-width: 800px) {

「ブラウザが」800pxを越える時まで有効です。

minは「最低でも必要」、maxは「この大きさまで有効」

PHPで自分のクラスを見たSingletonの生成

今更って感じですが。

<?php
class Foo
{
    /**
     * @brief 
     * @param 
     * @retval
     */
    static function getSingleton()
    {
        static $cache ;
        
        if (is_null($cache)){
            $cache = new static();
        }
        return $cache;
    }
    
    
    /**
     * @brief 
     * @param 
     * @retval
     */
    function whoisme()
    {
        return get_class($this);
    }
}

class A extends Foo
{
}

class B extends Foo
{
}

$a = A::getSingleton();
var_dump($a->whoisme()); 
$b = B::getSingleton();
var_dump($b->whoisme()); 


$c = A::getSingleton();
var_dump($c->whoisme()); 
$d = A::getSingleton();
var_dump($d->whoisme()); 

で、$c/$dは$aと同じクラスA。$bはクラスB

ORMとしてActiveObjectsを使用する

Atlassianのデータを保存する場所といえば、BandanaでありContentPropertyManagerである。

tohokuaiki.hateblo.jp

が、JIRA4.4からConfluence4.3からは特に意識しなくてもActiveObjectsが使えるようになった。こちらの方が早くて軽くて大容量でそのプラグイン固有のデータを保存して利用することができるということだ。

以下の記事をベースに使い方を見てみる。
Getting Started with Active Objects - Atlassian Developers

使えるようにするには

まず、pom.xmlDependencyを記述

<dependency>
  <groupId>com.atlassian.activeobjects</groupId>
  <artifactId>activeobjects-plugin</artifactId>
  <version>${ao.version}</version>
  <scope>provided</scope>
</dependency>

で、${ao.version}というのはこのURLから自由に選んでくれっていうことらしい。チュートリアルでは1.2.3を使っている。Confluence用っぽい0.24-m5-confluenceっていうのがあってこれを使うといいのだろうか・・・・。 https://maven.atlassian.com/content/repositories/atlassian-public/com/atlassian/activeobjects/activeobjects-plugin/

あと、なぜかGoogle.collectionsも入れておいてって言われた。

<!-- Google Collections, useful utilities for manipulating collections -->
<dependency>
  <groupId>com.google.collections</groupId>
  <artifactId>google-collections</artifactId>
  <version>1.0</version>
  <scope>provided</scope>
</dependency>

ActiveObjectsとして使用されるClassを指定

atlasian-plugin.xml

<ao key="ao-module">
  <description>The module configuring the Active Objects service used by this plugin</description>
  <entity>com.atlassian.tutorial.ao.todo.Todo</entity>
</ao>

というように、使用するActive Objects Classを記述する。上記の場合、com.atlassian.tutorial.ao.todo.TodoクラスがActiveObjectとなって使用されるようになる。

前述のClassを実装

atlassian-plugin.xmlで記述した com.atlassian.tutorial.ao.todo.Todo をinterfaceで実装する。

setter/getterでエンティティを定義。この時「ID」は net.java.ao.Entityが使っているのでよっぽどでない限りOverwriteはしない。

package com.atlassian.tutorial.ao.todo;

import net.java.ao.Entity;

public interface Todo extends Entity
{
    String getDescription();

    void setDescription(String description);

    boolean isComplete();

    void setComplete(boolean complete);
}

ServletXWorkで使用する場合の準備

Servletの場合

public final class TodoServlet extends HttpServlet
{

    private final ActiveObjects ao;


    public TodoServlet(ActiveObjects ao)
    {
        this.ao = checkNotNull(ao);
    }

という感じでいつものようにConstructorでInjectionする。このaoを使って先ほどのEntity化されたObjectをCRUDする。

XWorkの場合

XWorkの場合はConstructorによるInjectionが無いのでsetter/getterを使うかと思いきや、このActiveObjectsにはそれが使えないっぽい。なので一旦ActiveObjectsを使うClassをComponentとして登録する。

一旦Componentを作成する。

まずatlassian-plugin.xmlでcomponentとして登録する

<component key="foo-service" name="Foo-Service" class="jp.example.com.FooServiceImpl" public="true">
    <interface>jp.example.com.FooService</interface>
</component>

jp.example.com.Fooのinterfaceを作成し、jp.example.com.FooImplを実装する。public=trueでないならinterfaceは不要なわけだと思うけど。

で、こいつのConstructorにてActiveObjectsをInjectionしてもらう。

import static com.google.common.base.Preconditions.checkNotNull;


public class FooServiceImpl implements FooService {

    private final ActiveObjects ao;

    public FooServiceImpl(ActiveObjects ao) {
    this.ao = checkNotNull(ao);
    }

で、XWorkの方でこのComponentを読み込む

XWorkでsetter/getterを定義してComponentを使えるようにする。

import static com.google.common.base.Preconditions.checkNotNull;

    private FooService fooService;
    
    public FooService getFooService() {
        return fooService;
    }
    public void setFooService(FooService fooService) {
        this.fooService = checkNotNull(fooService);
    }