「アマゾン商品の情報」から、「当プラグイン用の商品の価格情報」を作成する

「アマゾン商品の情報」から、「当プラグイン用の商品の価格情報」を作成する処理について、PHPソースコードを解説しています。

「アマゾン商品の情報」は、以下の「商品の価格情報」を保持します。

  • Amazon.co.jpの価格
  • 最安値の価格
  • 中古価格

「当プラグイン用の商品の価格情報」を作成する際、上記の価格情報において、安い価格を優先して作成します。

目次
  1. 「アマゾン商品の情報」から、「当プラグイン用の商品の価格情報」を作成する
  2. 「商品の価格情報」は無いという情報を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する
  3. 「Amazon.co.jpの価格」を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する
  4. 「最安値の価格」を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する
  5. 「アマゾン商品の情報」が保持する「中古価格」に関する処理について、仕様外を示す例外を通知する
  6. 「安い方の価格」を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する
  7. 「アマゾン商品の情報」から、「Amazon.co.jpの価格」を作る
  8. 「アマゾン商品の情報」から、「最安値の価格」を作成する
  9. PriceResponse.phpのソースコード

「アマゾン商品の情報」から、「当プラグイン用の商品の価格情報」を作成する

public static function makePriceItem($searchItem, float $priceTime): PriceItem {

	$priceItem = new PriceItem ();

	if (isset ( $searchItem->Offers )) {
		$offers = $searchItem->Offers;
	} else {
		$offers = NULL;
	}

	// 参考:PA-API v4
	// 定価 価格:「ItemAttributes->ListPrice->Amount」「ItemAttributes->ListPrice->FormattedPrice」
	// Amazon.co.jp 価格:「Offers->Offer->OfferListing->Price->Amount」「Offers->Offer->OfferListing->Price->FormattedPrice」
	// マーチャント 新品の価格:「OfferSummary->LowestNewPrice->Amount」「OfferSummary->LowestNewPrice->FormattedPrice」
	//
	// PA-API v5
	// LowestUsedPriceは、無い。Condition ValueにUsedがあった。
	// Offers Listings Condition Value:Valid Values: New, Used, Collectible and Refurbished

	$priceFlag = 0b000;

	if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
			isset ( $offers->Listings [0]->Price ) and
			isset ( $offers->Listings [0]->Price->Amount )) {
		$priceFlag = $priceFlag | 0b001; // 「Amazon.co.jp 価格」が存在する。
	}

	if (isset ( $offers ) and isset ( $offers->Summaries ) and isset ( $offers->Summaries [0] ) and
			isset ( $offers->Summaries [0]->LowestPrice ) and
			isset ( $offers->Summaries [0]->LowestPrice->Amount )) {
		$priceFlag = $priceFlag | 0b010; // 「価格(最安値)」が存在する。
	}

	// if (isset($node->OfferSummary->LowestUsedPrice->FormattedPrice)) {
	// $priceFlag = $priceFlag | 0b100; //「マーチャント 中古の価格」が存在する。
	// }

	switch ($priceFlag) {
		case 0b000 :
			PriceResponse::setEmptyPriceTo ( $priceItem );
			break;
		case 0b001 :
		case 0b101 :
			PriceResponse::setAmazonPriceTo ( $priceItem, $offers );
			break;
		case 0b010 :
		case 0b110 :
			PriceResponse::setLowestPriceTo ( $priceItem, $offers );
			break;
		case 0b011 :
		case 0b111 :
			PriceResponse::setFitNewPriceTo ( $priceItem, $offers );
			break;
		case 0b100 :
			PriceResponse::setMerchantUsedPriceTo ( $priceItem, $offers );
			break;
		default :
			throw new IllegalArgumentException ( "無効な価格フラグ値:" . decbin ( $priceFlag ) );
	}

	if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
			isset ( $offers->Listings [0]->DeliveryInfo ) and
			isset ( $offers->Listings [0]->DeliveryInfo->IsFreeShippingEligible )) {

		$isFreeShippingEligible = $offers->Listings [0]->DeliveryInfo->IsFreeShippingEligible;
		if ($isFreeShippingEligible) {
			$priceItem->setPostageText ( "送料無料" );
		}
	}

	$priceItem->setPriceTime ( $priceTime );

	return $priceItem;
}

$searchItem変数は、「アマゾン商品の情報」を保持します。

その「アマゾン商品の情報」が保持する「商品の価格情報」から、
「当プラグイン用の商品の価格情報」を、作成します。

作成された「当プラグイン用の商品の価格情報」は、$priceItem変数が保持しています。

「アマゾン商品の情報」が保持する「商品の価格情報」には、以下の三種類があります。

  • Amazon.co.jpの価格
  • 最安値の価格
  • 中古価格

「当プラグイン用の商品の価格情報」を作成する場合、
価格の優先度は、安い価格を優先して作成します。

例えば「アマゾン商品の情報」において、

「Amazon.co.jpの価格」と「最安値の価格」の二つの価格情報がある場合、
安い方の価格を、「当プラグイン用の商品の価格情報」として作成します。

「商品の価格情報」が一つだけある場合は、
その価格を、「当プラグイン用の商品の価格情報」として作成します。

なお、現在のところ、中古価格を取り扱っていません。
当プラグインのショートコードが記述されている部分に、中古価格を表示しません。

「当プラグイン用の商品の価格情報」を保持するPriceItemクラス

「当プラグイン用の商品の価格情報」を保持する$priceItem変数は、PriceItemクラスの変数です。

class PriceItem {
	private $label = "";
	private $price = "";
	private $priceAddition = "";
	private $priceTime = 0;
	private $postageText = "";

以下省略

PriceItemクラスは、以下の「当プラグイン用の商品の価格情報」を保持します。

PriceItemクラスのメンバ変数PriceItemクラスのメンバ変数の説明
$label価格の名称(文字列)。

例:
価格
最安価格
$price価格(文字列)。

例:
1,000円
$priceAddition価格の付け足し情報(文字列)。

例:
より
「1,000円より」の「より」という文字列。
$priceTime「当プラグイン用の商品の価格情報」を作成した日時(float型)。

この日時は、Unixタイムスタンプ(マイクロ秒)です。

例:
1679921880.1234

この値は、おおよそ
2023年3月27日 21時58分
を示します。
$postageText送料(文字列)。

例:
送料無料
「当プラグイン用の商品の価格情報」を保持するPriceItemクラス

「商品の価格情報」の種類を示す、2進数で記述する$priceFlag変数

$priceFlag = 0b000;

$priceFlag変数は、ビットを表す0b文字列が付いています。
なので、整数を2進数で直接記述できます。

「アマゾン商品の情報」が保持する「商品の価格情報」は、三種類あります。
よって、$priceFlag変数は3ビットを直接記述しています。

ビットの各桁が意味する「商品の価格情報」は、以下の通りです。

$priceFlag変数のビット値$priceFlag変数のビット値が示す「商品の価格情報」
0b001Amazon.co.jpの価格
0b010最安値の価格
0b100中古価格

現在、未使用。
ビット値が示す「商品の価格情報」

$priceFlag変数の値は、ビットフラグと言われる値です。
ビットフラグとは、ビットの各桁に意味を持たせて、複数の情報を一つの整数で表現する方法です。

「アマゾン商品の情報」が保持する「商品の価格情報」に「Amazon.co.jpの価格」が存在する場合、$priceFlag変数の値に対して、「Amazon.co.jpの価格」を示すビットを立てる

$offers = $searchItem->Offers;

中略

$priceFlag = 0b000;

if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
		isset ( $offers->Listings [0]->Price ) and
		isset ( $offers->Listings [0]->Price->Amount )) {
	$priceFlag = $priceFlag | 0b001; // 「Amazon.co.jp 価格」が存在する。
}

$searchItem->Offers->Listings [0]->Price->Amountメンバー変数の例。

stdClass Object 
(
[ASIN] => XXXX000001

中略

[Offers] => stdClass Object 
( 
[Listings] => Array 
( 
[0] => stdClass Object 
( 
  [Price] => stdClass Object 
  ( 
  [Amount] => 4180 
  [Currency] => JPY 
  [DisplayAmount] => ¥4,180 
  ) 

中略

)

)
)
)

「アマゾン商品の情報」を保持する$searchItem変数に、
「Amazon.co.jpの価格」を保持するAmountメンバ変数が存在する場合、

「商品の価格情報」の種類を示す$priceFlag変数の値に対して、「Amazon.co.jpの価格」を示すビットを立てます。

$priceFlag = $priceFlag | 0b001; // 「Amazon.co.jp 価格」が存在する。

$priceFlag変数の値に対して、2進数の0b001を用いて論理和演算を行います。
ビット和の演算子 | を使って行います。

0b001は、「Amazon.co.jpの価格」を示すビット値です。

このビット値を使って論理和演算を行うことで、
例えば$priceFlag変数の値は、
0b000から
0b001になります。

ビットフラグを立てる論理和演算

ビットフラグを立てることによる情報管理方法とは、
整数型の変数の各ビットをオン/オフの状態にして、複数の情報を管理する方法です 。

ビットフラグを立てる論理和演算とは、ビット列の特定の位置に1をセットする操作のことです。

例えば、8ビットの数値00000000に対して、第3ビットを立てると00000100になります。

この操作は、ビット列と同じ長さのマスクと呼ばれるビット列を用意して、そのマスクの立てたいビットだけを1にして、元のビット列と論理和(OR)演算を行うことで実現できます。

例えば、
00000000と
00000100の論理和は
00000100になります。

論理和演算は、対応するビットがどちらか一方でも1であれば、結果も1になる演算です。

「アマゾン商品の情報」が保持する「商品の価格情報」に「最安値の価格」が存在する場合、$priceFlag変数の値に対して、「最安値の価格」を示すビットを立てる

$offers = $searchItem->Offers;

中略

$priceFlag = 0b000;

中略

if (isset ( $offers ) and isset ( $offers->Summaries ) and isset ( $offers->Summaries [0] ) and
		isset ( $offers->Summaries [0]->LowestPrice ) and
		isset ( $offers->Summaries [0]->LowestPrice->Amount )) {
	$priceFlag = $priceFlag | 0b010; // 「価格(最安値)」が存在する。
}

$searchItem->Offers->Summaries [0]->LowestPrice->Amountメンバー変数の例。

stdClass Object 
(
[ASIN] => XXXX000001

中略

[Offers] => stdClass Object 
( 
[Summaries] => Array 
( 
[0] => stdClass Object 
( 
  [LowestPrice] => stdClass Object 
  ( 
  [Amount] => 8350 
  [Currency] => JPY 
  [DisplayAmount] => ¥8,350 
  ) 
) 

中略

)
)
)

「アマゾン商品の情報」を保持する$searchItem変数に、
「最安値の価格」を保持するAmountメンバ変数が存在する場合、

「商品の価格情報」の種類を示す$priceFlag変数の値に対して、「最安値の価格」を示すビットを立てます。

$priceFlag = $priceFlag | 0b010; // 「価格(最安値)」が存在する。

$priceFlag変数の値に対して、2進数の0b010を用いて論理和演算を行います。
ビット和の演算子 | を使って行います。

0b010は、「最安値の価格」を示すビット値です。

このビット値を使って論理和演算を行うことで、
例えば$priceFlag変数の値は、
0b001から
0b011になります。

ちなみに2進数の0b011は、「商品の価格情報」が以下の二種類、どちらも存在することを示します。

  • Amazon.co.jpの価格
  • 最安値の価格

「商品の価格情報」を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する

switch ($priceFlag) {
	case 0b000 :
		PriceResponse::setEmptyPriceTo ( $priceItem );
		break;
	case 0b001 :
	case 0b101 :
		PriceResponse::setAmazonPriceTo ( $priceItem, $offers );
		break;
	case 0b010 :
	case 0b110 :
		PriceResponse::setLowestPriceTo ( $priceItem, $offers );
		break;
	case 0b011 :
	case 0b111 :
		PriceResponse::setFitNewPriceTo ( $priceItem, $offers );
		break;
	case 0b100 :
		PriceResponse::setMerchantUsedPriceTo ( $priceItem, $offers );
		break;
	default :
		throw new IllegalArgumentException ( "無効な価格フラグ値:" . decbin ( $priceFlag ) );
}

上記ソースコードのswitch文において、$priceFlag変数の値が示す「商品の価格情報」の種類を考慮して

「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、
適切な「商品の価格情報」を設定します。

$priceFlag変数の値が示す「商品の価格情報」の種類と、
$priceItem変数に設定される「商品の価格情報」の対応は、以下の表の通りです。

「商品の価格情報」の種類を示す$priceFlag変数の値$priceItem変数に設定される「商品の価格情報」
0b000 :「商品の価格情報」は無い。「商品の価格情報」は無いという情報が、
setEmptyPriceTo()関数によって、$priceItem変数に設定される。
0b001 :「Amazon.co.jpの価格」。
0b101 :「Amazon.co.jpの価格」と「中古価格」。
「Amazon.co.jpの価格」が、
setAmazonPriceTo()関数によって、$priceItem変数に設定される。
0b010 :「最安値の価格」。
0b110 :「最安値の価格」と「中古価格」。
「最安値の価格」が、
setLowestPriceTo()関数によって、$priceItem変数に設定される。
0b011 :「Amazon.co.jpの価格」と「最安値の価格」。
0b111 :「Amazon.co.jpの価格」と「最安値の価格」と「中古価格」。
「Amazon.co.jpの価格」と「最安値の価格」において、安い方の価格が、
setFitNewPriceTo()関数によって、$priceItem変数に設定される。
0b100 :「中古価格」。現在、未使用。
「商品の価格情報」の種類と、設定される「商品の価格情報」の対応

「送料無料」の文字列を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する

$offers = $searchItem->Offers;

中略

if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
		isset ( $offers->Listings [0]->DeliveryInfo ) and
		isset ( $offers->Listings [0]->DeliveryInfo->IsFreeShippingEligible )) {

	$isFreeShippingEligible = $offers->Listings [0]->DeliveryInfo->IsFreeShippingEligible;
	if ($isFreeShippingEligible) {
		$priceItem->setPostageText ( "送料無料" );
	}
}

※この記事を書いている時、$searchItem->Offers->Listings [0]->DeliveryInfo->IsFreeShippingEligibleメンバ変数の値を、取得することができませんでした。
後日、もしもDeliveryInfo->IsFreeShippingEligibleメンバ変数を取得できたら、ここにご紹介したいと思います。

「アマゾン商品の情報」を保持する$searchItem変数に、
「送料無料の対象を示す値」を保持するIsFreeShippingEligibleメンバ変数が存在する場合、

「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、「送料無料」の文字列を設定します。

$isFreeShippingEligible = $offers->Listings [0]->DeliveryInfo->IsFreeShippingEligible;
if ($isFreeShippingEligible) {
	$priceItem->setPostageText ( "送料無料" );
}

上記ソースコードでは、$isFreeShippingEligible変数に「送料無料の対象を示す値」を代入します。

$isFreeShippingEligible変数がtrueなら、
「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、「送料無料」を設定します。

$priceItem変数の例。(予想)

goodsmemo\item\PriceItem Object
  (

中略

    [postageText:goodsmemo\item\PriceItem:private] => 送料無料
  )

「当プラグイン用の商品の価格情報」を作成した日時を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する

$priceItem->setPriceTime ( $priceTime );

$priceTime変数は、「当プラグイン用の商品の価格情報」を作成した日時を保持します。

その日時を、$priceItem->setPriceTime()メソッドを使って、$priceItem変数に設定します。

ここで設定された日時は、
商品の価格情報が、いつの時点のものかを示す日時として、使用されます。

「いつの時点のものかを示す日時」の表示例。
価格: 980 円 2023年3月27日 21:58時点

$priceItem変数の例。

goodsmemo\item\PriceItem Object
  (

中略

    [priceTime:goodsmemo\item\PriceItem:private] => 1679921880.1234

中略

  )

「当プラグイン用の商品の価格情報」を作成した日時は、Unixタイムスタンプの値です

$priceTime変数は、Unixタイムスタンプ(マイクロ秒)の値を保持しています。

Unixタイムスタンプ(マイクロ秒)の値の例。
1679921880.1234

この値は、おおよそ
2023年3月27日 21時58分
を示します。

「商品の価格情報」は無いという情報を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する

private static function setEmptyPriceTo(&$priceItem) {

	$priceItem->setLabel ( "価格" );
	$priceItem->setPrice ( "" );
	$priceItem->setPriceAddition ( "" );
}

「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、「商品の価格情報」は無いという情報を設定します。

$priceItem->setPrice()メソッドを用いて、
「価格」に対して、「情報無し」を意味する空文字を設定します。

$priceItem->setPriceAddition()メソッドを用いて、
「価格の付け足し情報」に対して、「情報無し」を意味する空文字を設定します。

setEmptyPriceTo()関数の引数&$priceItem変数は、参照渡しされた変数です。

この関数内で、$priceItem変数が保持する値を変更すると、呼び出し元の$priceItem変数に対する変更となります。

$priceItem変数の例。(予想)

goodsmemo\item\PriceItem Object
  (
    [label:goodsmemo\item\PriceItem:private] => 価格
    [price:goodsmemo\item\PriceItem:private] => 
    [priceAddition:goodsmemo\item\PriceItem:private] => 

以下省略

  )

「Amazon.co.jpの価格」を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する

private static function setAmazonPriceTo(&$priceItem, $offers) {

	$priceItem->setLabel ( "価格" ); // スマートフォンの画面幅が狭いため、文字数を短くした。「Amazon.co.jp 価格」

	$amazonPrice = PriceResponse::makeAmazonPriceIfAmoutIsSet ( $offers );
	$formattedPrice = PriceUtils::makeFormattedPrice ( $amazonPrice );
	$priceItem->setPrice ( $formattedPrice );

	$priceItem->setPriceAddition ( "" );
}

「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、「Amazon.co.jpの価格」を設定します。

「Amazon.co.jpの価格」の文字列を、$priceItem変数に設定する

$amazonPrice = PriceResponse::makeAmazonPriceIfAmoutIsSet ( $offers );

$amazonPrice変数に、「Amazon.co.jpの価格」の文字列を代入します。

「Amazon.co.jpの価格」の文字列の例。
4180

「Amazon.co.jpの価格」の文字列は、makeAmazonPriceIfAmoutIsSet()関数によって作成されたものです。

$formattedPrice = PriceUtils::makeFormattedPrice ( $amazonPrice );

$formattedPrice変数に、整形された「Amazon.co.jpの価格」の文字列を代入します。

整形された「Amazon.co.jpの価格」の文字列の例。
4,180 円

整形された「Amazon.co.jpの価格」の文字列は、PriceUtils::makeFormattedPrice()関数によって作成されたものです。

PriceUtils::makeFormattedPrice関数()は、以下の整形処理をします。

  • 数値を3桁ごとにカンマで区切る。
  • 「円」文字を追加する。
$priceItem->setPrice ( $formattedPrice );

$priceItem->setPrice()メソッドを用いて、

「価格」に対して、
$formattedPrice変数が保持する、整形された「Amazon.co.jpの価格」の文字列を、設定します。

「価格の付け足し情報」を、$priceItem変数に設定する

$priceItem->setPriceAddition ( "" );

$priceItem->setPriceAddition()メソッドを用いて、

「価格の付け足し情報」に対して、
「情報無し」を意味する空文字を設定します。

$priceItem変数の例。

goodsmemo\item\PriceItem Object
  (
    [label:goodsmemo\item\PriceItem:private] => 価格
    [price:goodsmemo\item\PriceItem:private] => 4,180 円
    [priceAddition:goodsmemo\item\PriceItem:private] => 

以下省略

  )

「最安値の価格」を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する

private static function setLowestPriceTo(&$priceItem, $offers) {

	$priceItem->setLabel ( "最安価格" ); // 参考:PA-API v4の場合、新品価格

	$lowestPrice = PriceResponse::makeLowestPriceIfAmoutIsSet ( $offers );
	$formattedPrice = PriceUtils::makeFormattedPrice ( $lowestPrice );
	$priceItem->setPrice ( $formattedPrice );

	$priceItem->setPriceAddition ( "" );
}

「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、「最安値の価格」を設定します。

「最安値の価格」の文字列を、$priceItem変数に設定する

$lowestPrice = PriceResponse::makeLowestPriceIfAmoutIsSet ( $offers );

$lowestPrice変数に、「最安値の価格」の文字列を代入します。

「最安値の価格」の文字列の例。
8350

「最安値の価格」の文字列は、makeLowestPriceIfAmoutIsSet()関数によって作成されたものです。

$formattedPrice = PriceUtils::makeFormattedPrice ( $lowestPrice );

$formattedPrice変数に、整形された「最安値の価格」の文字列を代入します。

整形された「最安値の価格」の文字列の例。
8,350 円

$priceItem->setPrice ( $formattedPrice );

$priceItem->setPrice()メソッドを用いて、

「価格」に対して、
$formattedPrice変数が保持する、整形された「最安値の価格」の文字列を、設定します。

「価格の付け足し情報」を、$priceItem変数に設定する

$priceItem->setPriceAddition ( "" );

$priceItem->setPriceAddition()メソッドを用いて、

「価格の付け足し情報」に対して、
「情報無し」を意味する空文字を設定します。

$priceItem変数の例。(予想)

goodsmemo\item\PriceItem Object
  (
    [label:goodsmemo\item\PriceItem:private] => 最安価格
    [price:goodsmemo\item\PriceItem:private] => 8,350 円
    [priceAddition:goodsmemo\item\PriceItem:private] => 

以下省略

  )

「アマゾン商品の情報」が保持する「中古価格」に関する処理について、仕様外を示す例外を通知する

private static function setMerchantUsedPriceTo(&$priceItem, $offers) {

	throw new Exception ( "setMerchantUsedPriceTo()が、呼び出された。" );

	// $priceItem->setLabel("中古価格");
	//
	// $merchantPrice = PriceResponse::makeMerchantUsedPriceIfAmoutIsSet($offers);
	// $formattedPrice = PriceUtils::makeFormattedPrice($merchantPrice);
	// $priceItem->setPrice($formattedPrice);
	//
	// $priceItem->setPriceAddition("より");
}

setMerchantUsedPriceTo()関数は、仕様外の関数です。
よって、例外を通知しています。

以前、setMerchantUsedPriceTo()関数は、

「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、「中古価格」を設定する関数でした。

しかし現在のところ、当プラグインでは、「アマゾン商品の情報」が保持する「中古価格」を取り扱っていません。「中古価格」に関する処理は、未作成です。

現在において、仕様外である「中古価格」に関する処理が実行された場合、プログラムは誤動作します。これは、プログラムの不具合と言えます。

そのようなプログラムの不具合を見つけやすくするために、
万が一、「中古価格」に関する処理が実行された場合、例外を通知します。

エラーメッセージを見ることで、プログラムの不具合を修正しやすいからです。

※関連記事:Javaソースコードの条件分岐、プログラムで実行されない「その他の場合」のif文

今後、「中古価格」を取り扱う可能性があるから、setMerchantUsedPriceTo()関数を残しています

ソースコード上にsetMerchantUsedPriceTo()関数を残している理由は、

今後、「中古価格」を取り扱う可能性があるからです。

当プラグインで「中古価格」を取り扱わないと確定した場合は、ソースコード上からsetMerchantUsedPriceTo()関数を削除することになります。

仕様外のプログラムコードを残す方法

一般的なプログラミングにおいて、仕様外のプログラムコードと呼ばれるものがあります。

例えば、以下のものがあります。

  • 開発者が、自分のテストやデバッグのために作成したコード。
  • 将来的に再利用する可能性があるコード。
  • 他の開発者に参考にしてもらいたいコード。

このような仕様外のプログラムコードは、最終的な製品には含まれないものです。
つまり、不要なプログラムコードです。

最終的な製品にとって不要だけど、ソースコード上に残しておきたい。
そのような仕様外のプログラムコードを残す方法について、ちょっと調べてみました。

仕様外のプログラムコードを残す方法には、以下のような方法がありました。

  • コメントアウトする。
  • プリプロセッサディレクティブを使う。
  • 別のファイルに分離する。

仕様外のプログラムコードを、コメントアウトする

この方法は、

仕様外のコードの前に//や/*などの記号を付けて、コンパイラやインタプリタに無視させる方法です。

この方法は、一番手軽にできる方法と言えます。

ただし、コメントアウトされたコードがあちらこちらにあると、ソースコードの可読性や保守性を低下させます。

仕様外のプログラムコードに対して、プリプロセッサディレクティブを使う

この方法は、

仕様外のコードを#ifや#ifdefなどの条件文で囲んで、特定の条件下でのみで有効にする方法です。

例えば特定の条件下として、プログラムが開発バージョンの時だけ有効にします。
そうしたら、リリース版のプログラムに対して、仕様外のコードが有効になることはありません。

ただし、プリプロセッサディレクティブは、コードの動作や機能に影響を与える可能性があります。

例えば、特定の条件下で定義された変数や関数を他の場所で使用した場合、コンパイルエラーや実行時エラーが発生する可能性があります。

※なお、PHP言語には、プリプロセッサディレクティブと呼ばれる、コンパイル前にソースコードを変換する機能はありません。

仕様外のプログラムコードを、別のファイルに分離する

この方法は、

仕様外のコードがリリース版のプログラムに影響を与えないようにするとともに、将来的に再利用する可能性がある場合に備えて保管するための方法です。

別のファイルに分離する際には、以下の情報をコメントとして記述しておく、と良いです。

  • 仕様外のコードの目的や機能。
  • 作成日や作成者などのデータ。

これにより、仕様外のプログラムコードを管理しやすくなります。

「安い方の価格」を、「当プラグイン用の商品の価格情報」を保持する$priceItem変数に設定する

private static function setFitNewPriceTo(&$priceItem, $offers) {

	// Fit:ちょうど良い
	$amazonPrice = PriceResponse::makeAmazonPriceIfAmoutIsSet ( $offers );
	$lowestPrice = PriceResponse::makeLowestPriceIfAmoutIsSet ( $offers );

	if (is_numeric ( $amazonPrice ) && is_numeric ( $lowestPrice )) { // var_dump(is_numeric($amazonPrice));//var_dump(is_numeric($merchantPrice));
		$amazonPrice = intval ( $amazonPrice );
		$lowestPrice = intval ( $lowestPrice );

		if ($amazonPrice < $lowestPrice) {
			PriceResponse::setAmazonPriceTo ( $priceItem, $offers );
		} else {
			PriceResponse::setLowestPriceTo ( $priceItem, $offers );
		}
	} else {
		PriceResponse::setEmptyPriceTo ( $priceItem );
	}
}

「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、「安い方の価格」を設定します。

「安い方の価格」とは、「Amazon.co.jpの価格」と「最安値の価格」において、安い方の価格のことです。

$amazonPrice = PriceResponse::makeAmazonPriceIfAmoutIsSet ( $offers );
$lowestPrice = PriceResponse::makeLowestPriceIfAmoutIsSet ( $offers );

$amazonPrice変数に、「Amazon.co.jpの価格」の文字列を代入します。

「Amazon.co.jpの価格」の文字列の例。
4180

$lowestPrice変数に、「最安値の価格」の文字列を代入します。

「最安値の価格」の文字列の例。
8350

if (is_numeric ( $amazonPrice ) && is_numeric ( $lowestPrice )) {
	$amazonPrice = intval ( $amazonPrice );
	$lowestPrice = intval ( $lowestPrice );

以下省略
  • $amazonPrice変数が保持する、「Amazon.co.jpの価格」の文字列。
  • $lowestPrice変数が保持する、「最安値の価格」の文字列。

これらが数字文字列なら、文字列を数値に変換します。

例えば、文字列の"4180"を、数値の4180に変換します。

is_numeric()関数は、引数が数値または数値形式の文字列であるかどうかを、判定する関数です。

例えば、is_numeric(4180)はtrueを返します。
is_numeric("Hello")は、falseを返します。

intval()関数は、値を整数型に変換する関数です。

例えば、文字列や浮動小数点数型の値を整数型に変換できます。

if ($amazonPrice < $lowestPrice) {
	PriceResponse::setAmazonPriceTo ( $priceItem, $offers );
} else {
	PriceResponse::setLowestPriceTo ( $priceItem, $offers );
}
  • $amazonPrice変数が保持する「Amazon.co.jpの価格」。
  • $lowestPrice変数が保持する「最安値の価格」。

これらの価格を比較して、「安い方の価格」を、
「当プラグイン用の商品の価格情報」を保持する$priceItem変数に、設定します。

$amazonPrice変数の値が$lowestPrice変数の値より小さい場合、
「Amazon.co.jpの価格」は「安い方の価格」となります。

よって、setAmazonPriceTo()関数を用いて、$priceItem変数に「Amazon.co.jpの価格」を設定します。

$amazonPrice変数の値が$lowestPrice変数の値以上の場合、
「最安値の価格」は「安い方の価格」となります。

よって、setLowestPriceTo()関数を用いて、$priceItem変数に「最安値の価格」を設定します。

「Amazon.co.jpの価格」と「最安値の価格」が数字文字列でない場合、「安い方の価格」は存在しないと判断する

} else {
	PriceResponse::setEmptyPriceTo ( $priceItem );
}
  • $amazonPrice変数が保持する、「Amazon.co.jpの価格」の文字列。
  • $lowestPrice変数が保持する、「最安値の価格」の文字列。

これらが数字文字列でない場合、
「安い方の価格」は存在しない、と判断します。

よって、setEmptyPriceTo()関数を用いて、$priceItem変数に「商品の価格情報」は無いという情報を、設定します。

関数名が処理内容と一致せず、わかりにくいです

setFitNewPriceTo()という関数名は、関数の処理内容と一致せず、わかりにくいです。

この関数の処理内容は、
主に「安い方の価格」を$priceItem変数に設定する、となっています。

そういう意味では、例えば

setLowerPriceTo()という関数名の方がわかりやすい、と思います。

setFitNewPriceTo()関数を作成した当初、
新品の価格で最適なものを選んで設定する、ということを目指して関数を作成しよう、と思っていたようです。

ですが実際のところ、価格の安さだけを基準にして、最適な価格を設定するだけになりました。

「アマゾン商品の情報」から、「Amazon.co.jpの価格」を作る

//$offers = $searchItem->Offers;

private static function makeAmazonPriceIfAmoutIsSet($offers) {

	if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
			isset ( $offers->Listings [0]->Price ) and
			isset ( $offers->Listings [0]->Price->Amount )) {

		$priceAmount = $offers->Listings [0]->Price->Amount;
		return HTMLUtils::makePlainText ( ( string ) $priceAmount );
	} else {
		return "";
	}
}

$searchItem->Offers->Listings [0]->Price->Amountメンバー変数の例。

stdClass Object 
(
[ASIN] => XXXX000001

中略

[Offers] => stdClass Object 
( 
[Listings] => Array 
( 
[0] => stdClass Object 
( 
  [Price] => stdClass Object 
  ( 
  [Amount] => 4180 
  [Currency] => JPY 
  [DisplayAmount] => ¥4,180 
  ) 

中略

)

)
)
)

「アマゾン商品の情報」を保持する$searchItem変数に、
「Amazon.co.jpの価格」を保持するAmountメンバ変数が存在する場合、

makeAmazonPriceIfAmoutIsSet()関数は、
「アマゾン商品の情報」を保持する$searchItem変数から、「Amazon.co.jpの価格」の文字列を作成します。

$priceAmount = $offers->Listings [0]->Price->Amount;
return HTMLUtils::makePlainText ( ( string ) $priceAmount );

上記ソースコードでは、$priceAmount変数に「Amazon.co.jpの価格」を代入します。

HTMLUtils::makePlainText()関数に$priceAmount変数を渡して、「Amazon.co.jpの価格」の文字列をプレーンテキストに作り直します。

プレーンテキストに作り直した「Amazon.co.jpの価格」の文字列を、 return文で返します。

「Amazon.co.jpの価格」が存在しない場合、空文字を作成する

「アマゾン商品の情報」を保持する$searchItem変数に、
「Amazon.co.jpの価格」を保持するAmountメンバ変数が存在しない場合、

makeAmazonPriceIfAmoutIsSet()関数は、「Amazon.co.jpの価格」が存在しないことを示す空文字を、作成します。

空文字を、 return文で返します。

「アマゾン商品の情報」から、「最安値の価格」を作成する

//$offers = $searchItem->Offers;

private static function makeLowestPriceIfAmoutIsSet($offers) {

	if (isset ( $offers ) and isset ( $offers->Summaries ) and isset ( $offers->Summaries [0] ) and
			isset ( $offers->Summaries [0]->LowestPrice ) and
			isset ( $offers->Summaries [0]->LowestPrice->Amount )) {

		$lowestPriceAmount = $offers->Summaries [0]->LowestPrice->Amount;
		return HTMLUtils::makePlainText ( ( string ) $lowestPriceAmount );
	} else {
		return "";
	}
}

$searchItem->Offers->Summaries [0]->LowestPrice->Amountメンバー変数の例。

stdClass Object 
(
[ASIN] => XXXX000001

中略

[Offers] => stdClass Object 
( 
[Summaries] => Array 
( 
[0] => stdClass Object 
( 
  [LowestPrice] => stdClass Object 
  ( 
  [Amount] => 8350 
  [Currency] => JPY 
  [DisplayAmount] => ¥8,350 
  ) 
) 

中略

)
)
)

「アマゾン商品の情報」を保持する$searchItem変数に、
「最安値の価格」を保持するAmountメンバ変数が存在する場合、

makeLowestPriceIfAmoutIsSet()関数は、
「アマゾン商品の情報」を保持する$searchItem変数から、「最安値の価格」の文字列を作成します。

$lowestPriceAmount = $offers->Summaries [0]->LowestPrice->Amount;
return HTMLUtils::makePlainText ( ( string ) $lowestPriceAmount );

上記ソースコードでは、$lowestPriceAmount変数に「最安値の価格」を代入します。

HTMLUtils::makePlainText()関数に$lowestPriceAmount変数を渡して、「最安値の価格」の文字列をプレーンテキストに作り直します。

プレーンテキストに作り直した「最安値の価格」の文字列を、 return文で返します。

「最安値の価格」が存在しない場合、空文字を作成する

「アマゾン商品の情報」を保持する$searchItem変数に、
「最安値の価格」を保持するAmountメンバ変数が存在しない場合、

makeLowestPriceIfAmoutIsSet()関数は、「最安値の価格」が存在しないことを示す空文字を、作成します。

空文字を、 return文で返します。

PriceResponse.phpのソースコード

<?php

namespace goodsmemo\amazon\withoutsdk;

use Exception;
use goodsmemo\item\PriceItem;
use goodsmemo\item\html\PriceUtils;
use goodsmemo\item\html\HTMLUtils;
use goodsmemo\exception\IllegalArgumentException;

require_once GOODS_MEMO_DIR . "item/PriceItem.php";
require_once GOODS_MEMO_DIR . "item/html/PriceUtils.php";
require_once GOODS_MEMO_DIR . "item/html/HTMLUtils.php";
require_once GOODS_MEMO_DIR . "exception/IllegalArgumentException.php";

class PriceResponse {

	public static function makePriceItem($searchItem, float $priceTime): PriceItem {

		$priceItem = new PriceItem ();

		if (isset ( $searchItem->Offers )) {
			$offers = $searchItem->Offers;
		} else {
			$offers = NULL;
		}

		// 参考:PA-API v4
		// 定価 価格:「ItemAttributes->ListPrice->Amount」「ItemAttributes->ListPrice->FormattedPrice」
		// Amazon.co.jp 価格:「Offers->Offer->OfferListing->Price->Amount」「Offers->Offer->OfferListing->Price->FormattedPrice」
		// マーチャント 新品の価格:「OfferSummary->LowestNewPrice->Amount」「OfferSummary->LowestNewPrice->FormattedPrice」
		//
		// PA-API v5
		// LowestUsedPriceは、無い。Condition ValueにUsedがあった。
		// Offers Listings Condition Value:Valid Values: New, Used, Collectible and Refurbished

		$priceFlag = 0b000;

		if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
				isset ( $offers->Listings [0]->Price ) and
				isset ( $offers->Listings [0]->Price->Amount )) {
			$priceFlag = $priceFlag | 0b001; // 「Amazon.co.jp 価格」が存在する。
		}

		if (isset ( $offers ) and isset ( $offers->Summaries ) and isset ( $offers->Summaries [0] ) and
				isset ( $offers->Summaries [0]->LowestPrice ) and
				isset ( $offers->Summaries [0]->LowestPrice->Amount )) {
			$priceFlag = $priceFlag | 0b010; // 「価格(最安値)」が存在する。
		}

		// if (isset($node->OfferSummary->LowestUsedPrice->FormattedPrice)) {
		// $priceFlag = $priceFlag | 0b100; //「マーチャント 中古の価格」が存在する。
		// }

		switch ($priceFlag) {
			case 0b000 :
				PriceResponse::setEmptyPriceTo ( $priceItem );
				break;
			case 0b001 :
			case 0b101 :
				PriceResponse::setAmazonPriceTo ( $priceItem, $offers );
				break;
			case 0b010 :
			case 0b110 :
				PriceResponse::setLowestPriceTo ( $priceItem, $offers );
				break;
			case 0b011 :
			case 0b111 :
				PriceResponse::setFitNewPriceTo ( $priceItem, $offers );
				break;
			case 0b100 :
				PriceResponse::setMerchantUsedPriceTo ( $priceItem, $offers );
				break;
			default :
				throw new IllegalArgumentException ( "無効な価格フラグ値:" . decbin ( $priceFlag ) );
		}

		if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
				isset ( $offers->Listings [0]->DeliveryInfo ) and
				isset ( $offers->Listings [0]->DeliveryInfo->IsFreeShippingEligible )) {

			$isFreeShippingEligible = $offers->Listings [0]->DeliveryInfo->IsFreeShippingEligible;
			if ($isFreeShippingEligible) {
				$priceItem->setPostageText ( "送料無料" );
			}
		}

		$priceItem->setPriceTime ( $priceTime );

		return $priceItem;
	}

	private static function setEmptyPriceTo(&$priceItem) {

		$priceItem->setLabel ( "価格" );
		$priceItem->setPrice ( "" );
		$priceItem->setPriceAddition ( "" );
	}

	private static function setAmazonPriceTo(&$priceItem, $offers) {

		$priceItem->setLabel ( "価格" ); // スマートフォンの画面幅が狭いため、文字数を短くした。「Amazon.co.jp 価格」

		$amazonPrice = PriceResponse::makeAmazonPriceIfAmoutIsSet ( $offers );
		$formattedPrice = PriceUtils::makeFormattedPrice ( $amazonPrice );
		$priceItem->setPrice ( $formattedPrice );

		$priceItem->setPriceAddition ( "" );
	}

	private static function setLowestPriceTo(&$priceItem, $offers) {

		$priceItem->setLabel ( "最安価格" ); // 参考:PA-API v4の場合、新品価格

		$lowestPrice = PriceResponse::makeLowestPriceIfAmoutIsSet ( $offers );
		$formattedPrice = PriceUtils::makeFormattedPrice ( $lowestPrice );
		$priceItem->setPrice ( $formattedPrice );

		$priceItem->setPriceAddition ( "" );
	}

	private static function setMerchantUsedPriceTo(&$priceItem, $offers) {

		throw new Exception ( "setMerchantUsedPriceTo()が、呼び出された。" );

		// $priceItem->setLabel("中古価格");
		//
		// $merchantPrice = PriceResponse::makeMerchantUsedPriceIfAmoutIsSet($offers);
		// $formattedPrice = PriceUtils::makeFormattedPrice($merchantPrice);
		// $priceItem->setPrice($formattedPrice);
		//
		// $priceItem->setPriceAddition("より");
	}

	private static function setFitNewPriceTo(&$priceItem, $offers) {

		// Fit:ちょうど良い
		$amazonPrice = PriceResponse::makeAmazonPriceIfAmoutIsSet ( $offers );
		$lowestPrice = PriceResponse::makeLowestPriceIfAmoutIsSet ( $offers );

		if (is_numeric ( $amazonPrice ) && is_numeric ( $lowestPrice )) { // var_dump(is_numeric($amazonPrice));//var_dump(is_numeric($merchantPrice));
			$amazonPrice = intval ( $amazonPrice );
			$lowestPrice = intval ( $lowestPrice );

			if ($amazonPrice < $lowestPrice) {
				PriceResponse::setAmazonPriceTo ( $priceItem, $offers );
			} else {
				PriceResponse::setLowestPriceTo ( $priceItem, $offers );
			}
		} else {
			PriceResponse::setEmptyPriceTo ( $priceItem );
		}
	}

	private static function makeAmazonPriceIfAmoutIsSet($offers) {

		if (isset ( $offers ) and isset ( $offers->Listings ) and isset ( $offers->Listings [0] ) and
				isset ( $offers->Listings [0]->Price ) and
				isset ( $offers->Listings [0]->Price->Amount )) {

			$priceAmount = $offers->Listings [0]->Price->Amount;
			return HTMLUtils::makePlainText ( ( string ) $priceAmount );
		} else {
			return "";
		}
	}

	private static function makeLowestPriceIfAmoutIsSet($offers) {

		if (isset ( $offers ) and isset ( $offers->Summaries ) and isset ( $offers->Summaries [0] ) and
				isset ( $offers->Summaries [0]->LowestPrice ) and
				isset ( $offers->Summaries [0]->LowestPrice->Amount )) {

			$lowestPriceAmount = $offers->Summaries [0]->LowestPrice->Amount;
			return HTMLUtils::makePlainText ( ( string ) $lowestPriceAmount );
		} else {
			return "";
		}
	}

	private static function makeMerchantUsedPriceIfAmoutIsSet($offers) {

		throw new Exception ( "makeMerchantUsedPriceIfAmoutIsSet()が、呼び出された。" );

		// if (isset($node->OfferSummary->LowestUsedPrice->Amount)) {
		//
		// return HTMLUtils::makePlainText(
		// (string) $node->OfferSummary->LowestUsedPrice->Amount //例:object(SimpleXMLElement) public 0 => string '999' (length=3)
		// );
		// } else {
		//
		// return "";
		// }
	}
}