[PHP] EC-CUBEでテンプレート内からPHPを呼び、Smartyの変数を参照する方法。

※例によって、答えだけ知りたい方は、下のほうのコードまで読み飛ばしてください。

現在、EC-CUBEというオープンソースのショッピングカートシステムを利用してショッピングサイトの構築を行っております。

そこで問題になってきたのが、やはり・・・というべきか、Smartyが使われている点。
人によっては使いやすいのかもしれませんが、なんといっても自由度が低いことが難点の1つ。

特に、EC-CUBEのようなオープンソースのシステムで、Smartyを使われてしまってはオープンソースの利点の1つである「カスタマイズ性能」が著しく劣化する。

それなら、「EC-CUBEを使うな」と言われるかもしれませんが、Smartyであってもそれを補うだけのメリットがあるのもEC-CUBE
だからEC-CUBEを使うことはやめないと思う。
(もちろん時間と予算が許すなら自作したいが)

さて、私が疑問に思うことはみんなが疑問に思うことでもある。

EC-CUBEで実現したいことをGoogleでたくさん調べた。
どこのページを見たのかも分からなくなるくらい調べた。

そして、断念した。

検索により分かったことは、私と同じ疑問を抱き、多くの人が似たような質問をしている点。
そして、明確な答えが得られていない点。

そこで私は、ソースに目を移した。
呼び出されているファイルを順番にトレースしていく。

そう、事件はGoogleで起きているんじゃない!ソースで起きているんだ!

ソースには答えが書かれている。
答えは思ったよりも簡単だった。
これで好き放題できるというものだ。

ちょっとした前提(1)

実は、私は、EC-CUBEの【商品登録】において画像のアップロードは行っていない。
商品は全てExcelで管理し、EC-CUBEのインポート機能を用いて行う。

画像は下記のような構成で、一括してFTPしている。
image
∟ items
∟ 13 ・・・ 商品ID
∟ item_s.jpg ・・・ 画像小
∟ item_m.jpg ・・・ 画像中
∟ item_l.jpg ・・・ 画像大
∟ sub01.jpg ・・・コメント画像1
∟ sub02.jpg ・・・コメント画像1
∟ 21 ・・・ 商品ID
∟ 101 ・・・ 商品ID

このようにすると、当然EC-CUBEのテンプレートファイル内に<img>タグを自前で埋め込む必要がある。
他の場面でもこんなことをやっているから、EC-CUBEを使っているとは思えないような、ユーザーインターフェースになっている。

webデザイナーにはこう伝えてある。
「売れるデザインを第一に、どんなものでも好きに作ってください」と。
「どんな無理難題でも作りますから、その代わり、”売れるデザイン”にしてください。」と。

ちょっとした前提(2)

忘れてはいけないのが、EC-CUBEがオープンソースだってこと。
そして、まだ開発が続けられているってこと。

それが意味するものは、バージョンアップに対応できなければいけないってこと。
だから、コアな部分に手を加えて「バージョンアップできません」では話しにならない。

それを回避するために、
EC-CUBEが用意しているものは最大限に利用する。
EC-CUBEが提供している、「カスタマイズして良いエリア」からはみ出す事のないようにする。
これが大事。

そして用意されているのが、テンプレートファイル(*.tpl)
カスタマイズは、極力テンプレートファイル内で収めたい。

そこで、問題が発生する。
Smartyだ!

Smartyだから、正面からぶつかっていったのでは、弾き飛ばされる。
ここで断念しているケースをGoogleでよく見かけた。

で、本題。

【本題1】EC-CUBEのテンプレートファイル内でPHPを実行する

そう、テンプレートファイルの中で、単純なPHPコードの実行さえ許されていないのだ。
いや、正確には許されているが、それはEC-CUBEではなく、Smartyを知っていなければならない。

テンプレートファイル内にて

<!--{php}-->
$test = 'テストです。';
echo $test;
<!--{/php}-->

こう。
<?php にあたる部分が、<!--{php}-->
であり、
?> にあたる部分が、<!--{/php}-->
である。

【本題2】EC-CUBEのテンプレートファイル内から外部変数を参照する

テンプレートファイルの中でPHPコードを実行できたと思ったら、すぐさま新たな問題に直面することだろう。

なぜならテンプレートの中で使われている、Smarty側の変数にアクセスできないからだ。

<!--{$arrProduct.product_id}-->

テンプレート内には、このような箇所を見つけることがあるだろう。
そして、

<!--{php}-->
echo $arrProduct.product_id;
<!--{/php}-->

とやってもうまく動作しない。
なぜなら、$arrProduct がいる場所がこのスコープに無いからだ。

だからといって、

<!--{php}-->
global $arrProduct;
echo $arrProduct.product_id;
<!--{/php}-->

とやってもうまく動作しない。
そんなものは定義されていないからだ。

ではどうするか。

その前に、サンプルコードの場所を明示しておきます。
/data/Smarty/templates/default/detail.tpl
このファイルをいじります。
このファイルは、商品詳細ページのテンプレートファイルです。

ファイルを開いたら、【 {$arrProduct[$key]|escape} 】を検索してみてください。

この場所は、ループにて「サブ説明1~5」を表示している箇所です。
このループ中に例によってPHPコードを埋め込むことは可能なのですが、PHPコード側から $key の値を知る方法がありません。
$key が分からないことには、ループ中にコードを埋め込めても、やりたいことはできないと思います。

ちなみに私はループ中で、 あるディレクトリ内に comment_$key.jpg が見つかれば画像表示、なければ非表示。
画像の有無で 、<div> のclassを変えるという処理を加えています。

これを実現するためには、$key の値を知る必要があります。

でも・・・。
Googleで調べただけでは分かりませんでした。

EC-CUBEのテンプレ内で外部の変数を扱うための方法

ようするに、$key の値が分からなくても、自前でループを用意してやればいいわけです。

Googleは諦め、EC-CUBEのソースを読んでいて分かったことは、$objPage というオブジェクトが作られているということです。
このオブジェクトのクラスの中で何が行われているか分かれば、答えに辿りつくまでそう時間はかかりませんでした。

試しに、テンプレートファイルの中で次のように書いてみました。

<!--{php}-->
global $objPage;
print_r($objPage->arrProduct);
<!--{/php}-->

みなさんもこのように書いて実行してみてください。
そして、ブラウザからソースを開いて確認してください。

そこには、arrProduct の中の配列が記述されていることが分かります。

・・・ということは・・・。
はい。
print_r() で出力されるということは・・・。

参照できてますね。

ここまで出来さえすれば、もうあなたの好き放題に、$objPage の中をいじり倒すことができるでしょう。

ちなみに、「detail.tpl」における「$objPage」のクラスファイルは、
/data/class/pages/products/LC_Page_Products_Detail.php
に置かれています。

2009/08/20 2:20 追記

twitterにて、ゆーき様からアドバイスを頂きました。
global $objPage; としなくても、

$arrProduct = $this->get_template_vars('arrProduct');
print_r($arrProduct);

で、同じことができました。
どちらを使うかは、皆さんにお任せします。(どちらでも良いと思いますので)