Windows+PHP+memcached+symfony

PHPマニュアル memcache

Windows用のmemcachedもバイナリパッケージで入手できるもんですね。手元の開発環境でどうしようかと思ったら、なんでもあるもんだ。

memcached-win32 Windows用のmemcached。サービス版とコマンド版両用 バイナリ版をzipで展開して適当な場所に置く

peclのWindows用バイナリ配布pecl4win からmemecahed拡張をダウンロード。5.2.5用はないので5.2.1用を。php-5.2.5/extとかに置く。

php.iniを編集して、extention=php_memcache.dll を追加。(Apache再起動)(このバイナリのdllにはmemcacheで”d”はついてないので注意)

sfMemcachePluginを、自分のsymfonyで作ったプロジェクトに入れる。

> symfony plugin-install http://plugins.symfony-project.com/sfMemcachePlugin

関数キャッシュのmemcached化の使用レポートin日本語を参考に、設定を行なう。

config_handlers.ymlとmemcache.ymlを、(アプリ名)/config/ にコピー。memcache.ymlの中のポート番号などは自分が動かしているmemcachedの設定に合わせて変更する。

conf/factories.ymlで、ViewをキャッシュするクラスをsfMemcacheCacheに置換する。

view_cache:
  class: sfMemcacheCache

もちろん、自分のsymfony appはテンプレートキャッシュを使う設定になってないといけない。開発環境でもcacheをオンにする設定は、たとえば、(apps)/settings.ymlにて

all:
  .settings:
    cache:     on

(apps)/cache.ymlにて

all:
  enabled:     on
  with_layout: false
  lifetime:    86400

など。(実際にはこんな乱暴に全actionにキャッシュをかけちゃだめ)

あとは、設定を反映させるために、symfonyキャッシュをクリア

> symfony cc

で、実行する。devモードの場合、一回目表示される水色の「キャッシュがなかったので作ったよ」マークが二回目の表示で黄色になればOK。

実行した結果、memcachedが本当に使われているかどうかを確認するには、memcachedの内容を確認するにはにあるようなスクリプトでmemcachedの状態を表示します。

[追記] クライアント側のライブラリだからdがついてない、とelfさんに指摘いただきました。考えてみればそうですね。

symfonyのフォームでYahoo UIの綺麗なボタンを使う

状況

  • フォームのボタンをブラウザのデフォルトじゃなく、もうちょっと良いデザインにしたい
  • Yahoo UIのボタンは、CSSでキレイにデザインされている。CSSや画像ファイルもyahoo.comのを使えるのでサーバにもやさしい
  • symfonyで作ったフォームからYUI buttonを使いたい

symfonyでのフォームのsubmitについては、link_to()、button_to()、submit_image_tag()の3つがFormHelperに用意されています。

  • submit_tag() は、ブラウザデフォルトのボタンを書くのでフォームでそのまま動く
  • button_to() type=”button”は作れるけど、formの値を送るには自分でjavascript書く必要あり
  • submit_image_tag() 画像用意すればキレイなsubmit用のボタンが使える

YUI buttonは、type=”button”を使うことを前提にしているのですが、type=”button”でformのサブミットをさせる(ボタンを押したらフォームの各値がリクエストに含まれる)ようにするためには、ボタンが所属するフォームを駆動するようなJavascriptが必要となります。

以上から、次のようにすることで、symfony+YUIでのCSSデザインボタンを作ることができました。

HTMLのほうは、2番目のパラメータにtypeを渡すことで、submit_tag()にもtype=”body”を上書きで指定することができます。

<?php echo submit_tag('実行する', array('type' => 'button', 'id' => 'compareButton')); ?>

YUI buttonのJavascriptでの定義のところでは、この「フォームを駆動するボタン」という設定ができるので、これを指定します。

<script type="text/javascript">
var oButton = new YAHOO.widget.Button(
  "compareButton",
  { 
    checked: false,
    type: "submit"
  }
);
</script>

type: “submit”がそれにあたります。

あとは、YUI buttonに必要な定義をします。

なんらかのスタイルをあてる。YUIで提供されているスキンか、自分で改造したスキンを指定することも可能

<body class="yui-skin-sam">

symfonyのconfig/view.ymlでは、関係のあるYUIのCSS/JSを読ませるようにします。

  stylesheets:    [main, http://yui.yahooapis.com/2.4.1/build/grids/grids-min.css, http://yui.yahooapis.com/2.4.1/build/button/assets/skins/sam/button.css]

  javascripts:    [http://yui.yahooapis.com/2.4.1/build/yahoo-dom-event/yahoo-dom-event.js, http://yui.yahooapis.com/2.4.1/build/element/element-beta-min.js, http://yui.yahooapis.com/2.4.1/build/button/button.js]

このへんは、YUIのバージョン変わったり、圧縮版を使うかとか、yahoo.comの提供してくれているファイルを使うか、ローカルにコピーしたファイルを使うかとかで変わってくるでしょう。

symfony, YUIで作ったキレイ目ボタン

symfonyで、view.ymlで定義したサイトタイトルをテンプレート中から呼び出す方法

view.ymlのdefault/metas/titleでサイトワイドのタイトルを定義しているのに、layout.phpや_header.phpでタイトルを手打ちするのは嫌だなあ、ということで、どこから辿ってview.ymlのデータが取れるのかを探しました。

layout.php等で、

sfContext::getInstance()->getResponse()->getTitle()

を呼ぶと、view.ymlの中のタイトルが取れます。これを<h1>とかに放り込めばOK。

SimpleXMLElementをunserializeするとエラーになる

simplexmlで取得したオブジェクトをシリアライズしても、元に戻せない。

$gottenItems = simplexml_load_file($serviceUrl);
$hoge = unserialize(serialize($gottenItems));

エラーはこれ

Warning: unserialize() [function.unserialize]: Node no longer exists in *.php on line *

simplexml_load_stringのマニュアルのコメントでも回避策とか提案されている。

なんでこんなエラーに出会ったかというと、symfonyの関数キャッシュを使おうとしたら、対象の関数の返すのがsimplexml_load_file()の返すオブジェクトそのままだったからで、symfonyの中でエラーになった。

以下のコードは、検索結果をファイルにキャッシュする関数をsymfonyで書いたもの。symfonyのキャッシュフォルダ以下に生成させることで、キャッシュコントロールをsymfony管理下に置いている。

public static function search($words, $offset = 0, $results = 10) {
	$function_cache_dir = sfConfig::get('sf_cache_dir').'/mysearch';
	$fc = new sfFunctionCache($function_cache_dir);
	$results = $fc->call('doSearch', $words, $offset, $results);
	return $results;
}

コメントにあった回避策取るよりは、そもそもシリアライズするポイントが間違ってる、ということかなと。

XMLのままキャッシュに入れるか、SimpleXMLElementから必要なものを取り出してその配列やオブジェクトをserializeするように変更しよう。