Caution: You are browsing the legacy symfony 1.x part of this website.

ショッピングカートを管理する方法

1.2
Symfony version Language

概要

symfonyはEコマースのWebサイトのショッピングカートを管理するプラグインを提供します。 アイテムを追加し、量を変更しショッピングカートの内容を表示する機能を作るのは苦痛なしで簡単にできます。

インストール方法

ショッピングカートクラスはデフォルトのsymfonyインストールに搭載されていませんが、sfShoppingCartと呼ばれるプラグインパッケージがあります。 symfonyプラグインはPEARを通してインストールされます(プラグインについて詳細な内容は17章で見つかります)。

sfShoppingCartプラグインのインストールはプラグインのページで説明されているように、とてもわかりやすいです。 必要なのは次のコマンドラインを入力するあるだけです:

$ symfony plugin:install sfShoppingCartPlugin

プラグインクラスのオートロード機能を有効にするためにキャッシュをクリアします:

$ symfony cc

コンストラクタ

sfShoppingCartクラスはショッピングカートを管理することを目的としています。 さまざまな種類のオブジェクトを格納できます。

コンストラクタによってショッピングカートに適用する税率を宣言できます:

$my_shopping_cart = new sfShoppingCart(sfConfig::get('app_cart_tax'));

この例において、ショッピングカートの税率は簡単に変更するためにアプリケーションのapp.xml設定ファイルに書き込みます:

all:
  cart:
    tax:  19.6

ユーザーのショッピングカートを作成する

newコンストラクタによるアクションで新しいsfShoppingCartオブジェクトを簡単に作成できます。 しかしながら、ユーザーセッションにリンクされないのであれば何の役にも立ちません。 ショッピングカートでユーザーの選択を保持するもっとも簡単な方法はsfShoppingCartオブジェクトのコンポジションsfUserオブジェクトにすることです。 それを行うためには、カスタムメソッドをmyproject/apps/myapp/lib/myUser.phpクラスに追加してください:

class myUser extends sfUser
{
  public function getShoppingCart()
  {
    if (!$this->hasAttribute('shopping_cart'))
    {
      $this->setAttribute('shopping_cart', new sfShoppingCart(sfConfig::get('app_cart_tax')));
    }
 
    return $this->getAttribute('shopping_cart');
  }
 
  // ...
}

ユーザーがまだ作成されていなければ$user->getShoppingCart()メソッドは新しいショッピングカートを作成します。

note

カスタムのmyUserクラスでデフォルトのsfUserクラスをオーバーライドする方法についてもっと詳しい情報が必要でしたら、17章ファクトリのセクションをご覧ください。

アイテムを追加、修正、削除する

ショッピングカートは異なるクラスからのオブジェクトの量を収納できます。 ショッピングカートに保存されたそれぞれのアイテムはsfShoppingCartItemクラスのインスタンスです。

sfShoppingCartクラスはaddItem()deleteItem()メソッドを持ちます。 任意のタイプのオブジェクトを追加もしくは削除できるので、これらのメソッド呼び出しの最初の引数はオブジェクトのクラスの名前です。

1つのアイテムの量を修正するには、(sfShoppingCartオブジェクトのgetItems()メソッド経由で)sfShoppingCartItemオブジェクト自身を取得しsetQuantity()メソッドを呼び出します。

ショッピングカートモジュール

Productクラス(製品を表す)のオブジェクトがaddupdatedeleteアクションによって追加、修正もしくは制限できるショッピングカート管理モジュールの実装は次のとおりです:

class shoppingcartActions extends sfActions
{
  // ...
 
  public function executeIndex()
  {
    $this->shopping_cart = $shopping_cart;
    $this->items = $shopping_cart->getItems();
 
    // ...
  }
 
  public function executeAdd($request)
  {
    // ...
 
    if ($request->hasParameter('id'))
    {
      $product = ProductPeer::retrieveByPk($request->getParameter('id'));
      $item = new sfShoppingCartItem('Product', $request->getParameter('id'));
      $item->setQuantity(1);
      $item->setPrice($product->getPrice());
      $shopping_cart = $this->getUser()->getShoppingCart();
      $shopping_cart->addItem($item);
    }
 
    // ...
  }
 
  public function executeUpdate($request)
  {
    $shopping_cart = $this->getUser()->getShoppingCart();
    foreach ($shopping_cart->getItems() as $item)
    {
      if ($request->hasParameter('quantity_'.$item->getId()))
      {
        $item->setQuantity($request->getParameter('quantity_'.$item->getId()));
      }
    }
 
    // ...
  }
 
  public function executeDelete($request)
  {
    if ($request->hasParameter('id'))
    {
      $shopping_cart = $this->getUser()->getShoppingCart();
      $shopping_cart->deleteItem('Product', $requets->getParameter('id'));
    }
 
    // ...
  }
 
  ...
}

アイテムを追加する

このコードをより詳しく見てみましょう。

ショッピングカートにアイテムを追加するために、addItem()メソッドを呼び出し、sfShoppingCartItemオブジェクトを渡します。このオブジェクトはオブジェクトクラス、追加されるアイテムのユニークID、追加される量、アイテムの価格を含みます。 このことによってショッピングカートは任意のクラスのオブジェクトを持つことができます。 この例においては、本とCDを含むショッピングカートを持つことができます。

バックオフィスにおいて製品の価格が修正される場合(もしくはカートがセッション期間を保持する場合)、製品追加時と会計時の間の価格の変動を避けるためにこの瞬間の価格は保存されます。 これによって顧客が注文した量に応じて割り引きすることも可能になります:

if ($quantity > 10)
{
  $item->setPrice($product->getPrice() * 0.8);
}
else
{
  $item->setPrice($product->getPrice());
}

問題はこの方法で割引する場合オリジナルの価格を失われることです。 sfShoppingCartItemオブジェクトが割引率を要求するsetDiscount()メソッドを持つ理由です:

if ($quantity > 10)
{
  $item->setPrice($product->getPrice());
  $item->setDiscount(20);
}
else
{
  $item->setPrice($product->getPrice());
}

アイテムを修正する

アイテムの量を変更するには、sfShoppingCartItemオブジェクトのsetQuantity()メソッドを使います。 アイテムを削除するには、deleteItem()メソッドを呼び出す、もしくはsetQuantity(0)メソッドを呼び出して量を0に変更します。

ユーザーが同じアイテム(同じクラスと同じid)を何度も追加する場合、ショッピングカートはアイテムの量を増やし、新しいアイテムは追加しません:

$item = new sfShoppingCartItem('Product', $request->getParameter('id'));
$item->setQuantity(1);
$item->setPrice($product->getPrice());
$shopping_cart = $this->getUser()->getShoppingCart();
$shopping_cart->addItem($item);
$shopping_cart->addItem($item);
 
// 同上
 
$item = new sfShoppingCartItem('Product', $request->getParameter('id'));
$item->setQuantity(2);
$item->setPrice($product->getPrice());
$shopping_cart = $this->getUser()->getShoppingCart();
$shopping_cart->addItem($item);

結局、updateアクションが'id=2313&quantity=4'の代わりに'quantity_2313=4'のような引数を使用するのはなぜなのかと不思議に思うかもしれません。 当然のことながら、このアクションが実装されている方法によって一度に複数の記事の量の更新が可能です。

ショッピングカート全体を削除する

ショッピングカートをリセットするにはsfShoppingCartインスタンスのclear()メソッドを呼び出します。

$this->getUser()->getShoppingCart()->clear();

テンプレートにショッピングカートを表示する

shoppingcart/indexアクションはショッピングカートの内容を表示します。 実現可能な実装を試してみましょう。

ショッピングカートの内容を取得する

sfShoppingCartオブジェクトの3つのメソッドがショッピングカートの内容の取得を手助けしてくれます:

  • ショッピングカートのsfShoppingCartItemオブジェクトすべての配列
  • ->getItem($class_name, $object_id): 1つの特定のsfShoppingCartItemオブジェクト
  • ->getTotal(): ショッピングカートの総量(アイテムごとの量×価格の合計)

ショッピングカートのアイテムはパラメーターホルダーを保持します。 このことはカスタムの情報をどのアイテムにも追加できることを意味します。

たとえば、自動車の部品を売るWebサイトにおいて、sfShoppingCartItemオブジェクトは追加されたオブジェクトを保存する必要がありますが、部品が購入された乗用車も保存します。 これは次のコードを追加することでシンプルに行われます:

$item->setParameter('vehicle', $vehicle_id);

note

getItems()メソッドの代わりにgetObjects()が必要かもしれません。 このメソッドは存在しますが、Propelデータアクセスレイヤーに依存します。 Propelの利用はオプションなので、これを使用することはできないかもしれません。 データアクセスレイヤーについては8章でもっと多くのことを学んでください。

テンプレートに値を渡す

ショッピングカートの内容を表示するために、indexアクションはテンプレートにアクセスできる変数をいくつか定義しなければなりません:

// ...
 
$this->shopping_cart = $shopping_cart;
$this->items = $shopping_cart->getItems();

次の例はそれぞれのアイテムについての情報を示すショッピングカートのすべてのアイテムについてのイテレーションに基づいたindexSuccess.phpテンプレートを示しています:

<?php if ($shopping_cart->isEmpty()): ?>
 
  Your shopping cart is empty.
 
<?php else: ?>
 
  <?php foreach ($items as $item): ?>
    <?php $object = call_user_func(array($item->getClass().'Peer', 'retrieveByPK'), $item->getId()) ?> 
    <?php echo $object->getLabel() ?><br />
    <?php echo $item->getQuantity() ?><br />
    <?php echo currency_format($item->getPrice(), 'EUR' ) ?> 
    <?php if ($item->getDiscount()): >
       (- <?php echo $item->getDiscount() ?> %)
    <?php endif; ?><br />
  <?php endforeach; ?>
 
  Total : <?php echo currency_format($shopping_cart->getTotal(), 'EUR' ) ?><br />
 
<?php endif; ?>

この例ではPropelデータアクセスレイヤーが使用していることに注目してください。 あなたのプロジェクトが他のデータベースアクセスレイヤーを使用している場合、この例を修正することが必要になることがあります。

税金有りもしくは無し

デフォルトでは、すべての実行($shoppinng_cart->addItem()に加えて、$get->getPrice()$shopping_cart->getTotal()によるアクセス)は税金無しで価格を使います。

税金を含めた合計金額を取得するために、次のコードを呼び出さなければなりません:

$total_with_taxes = $shopping_cart->getTotalWithTaxes()

必要な場合、sfShoppingCartオブジェクトは初期化されaddgetメソッドは税金を含む価格を使います:

class myUser extends sfUser
{
  public function getShoppingCart()
  {
    if (!$this->hasAttribute('shopping_cart'))
    {
      $this->setAttribute('shopping_cart', new sfShoppingCart(sfConfig::get('app_cart_tax')));
    }
    $this->getAttribute('shopping_cart')->setUnitPriceWithTaxes(sfConfig::get('app_cart_withtaxes'));
 
    return $this->getAttribute('shopping_cart');
  }
 
  // ...
}

sfConfig::get('app_cart_withtaxes')trueに設定される場合、$shopping_cart->addItem()$item->getPrice()メソッドは税を含む価格を使います。 getTotal()getTotalWithTaxes()メソッドはまだ正しい結果を返します。

繰り返しますが、設定ファイルに税の設定を保存することはよい習慣です: 上記の例ではシンプルなtrueの代わりにsfConfig::get('app_cart_withtaxes')を使うのはそういうわけです。 myproject/apps/myapp/config/app.ymlは次の内容を含みます:

all:
  cart:
    tax:       19.6
    withtaxes: true

税が処理される方法に信頼がおけない場合、ショッピングカートに尋ねてください:

$uses_tax = $shopping_cart->getUnitPriceWithTaxes();