My365のサーバサイドのプログラムはPHPで書きました。
(よかったらこちらもどうぞ → iOS編, サーバ編 )
開発環境
開発環境は、Aptana Studio 3を使っています。2ではPHPのプラグインを追加して使っていましたが、3は確か標準でPHPに対応しました。下部にターミナルを備えていて、バージョン管理などをここから行ったりしています。Windowsでもこのターミナル部分はLinuxライクに使えて、コマンドプロンプトを使わざるを得ない場面で役に立ったりします。
なぜAptanaを使っているかといえば、PHPの補完とコードフォーマットが便利だからです。おすすめします。
フレームワーク
フレームワークは名もない自作フレームワークを使用しています。
PHPといえばCakePHPなどの有名なフレームワークがあるのですが、以前に使ってみて馴染まなかったので、自作することにしました。(choilogというブログサービスはCakePHPで書きました)
フレームワークを使うからには、できるだけフレームワークのやり方に従うべきだと思います。そういうわけで、できるだけCakePHPらしくプログラムを書いていたのですが、「らしく書いているつもりが動かない」ということが度々ありました。色々調べてみるのですが、結局はソースコードを読むハメになっていました。
そういう時間は苦痛で仕方ないので、CakePHPとほとんど同じように使えて最小限の部分だけを切り出したようなフレームワークを作り、その上で動かすことにしました。だから、構成とかは良く似ています。
ディレクトリ構造
app/ ├─ action/ --- アクションクラス ├─ config/ --- 各種定数や環境設定ファイル ├─ element/ --- ビューの中で共通して使う部品 ├─ helper/ --- ビュー出力の補助クラス ├─ layout/ --- ビューの外で共通して使うレイアウト ├─ lib/ --- PEAR,OAuth,S3 SDKなどのライブラリ ├─ locale/ --- 言語ファイル ├─ model/ --- モデルクラス ├─ view/ --- ビューファイル ├─ app.php └─ controller.php
言語×デバイス
特に力を入れたのが言語の切り替えとデバイスの切り替えの部分です。現在のアクセスは、以下の4通りに分けています。
- PC×日本語
- PC×英語
- iPhone×日本語
- iPhone×英語
今後、他の言語に広げたり、他のデバイスに対応させたいと考えていますので、このあたりをフレームワークで吸収してしまいたいと考えました。
多言語対応
言語は、国際化用拡張モジュール(Intl)のlocale_accept_from_httpという関数を使って、リクエストヘッダーから取得します。取得できなかった場合は標準で英語”en”としています。
$language = locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE']);
if (!in_array($language, LocaleConfig::$language))
$language = LocaleConfig::$language[0];
言語データは、別ファイルに連想配列で保持しています。例えばトップページの場合はこんな具合です。
// locale/teaser.php
return array(
'News20110505' => array(
'en' => 'We started developing My365!',
'ja' => 'My365の開発に着手!',
),
// ...(略)...
'Tweet' => array(
'en' => '1 Day, 1 Photo. My365',
'ja' => '一日一枚、印象的な瞬間を写真におさめてカレンダーに残す、思い出共有アプリ「My365」'
)
);
表示させる時はviewファイルの中に次のように書いて、 locale/teaser.php の連想配列のキー News20110505 からユーザーの言語に対応する文字列を取得して表示します。
// view/pc/teaser.php
String('teaser', 'News20110505');?>
画像データに文字列を埋め込むこともありますので、画像ファイルも言語ごとに用意しています。たとえば、次のように書けば、日本語環境では /img/ja/teaser/spacer.gif を読み込むようになります。CSSは多言語化されていないので、デザイナーの @t_ishiyama に「今はCSSから読み込む画像に文字列を入れないでくれ」とお願いしました。
// view/pc/teaser.php
Image('teaser/spacer.gif', array('width' => '1', 'height' => '366')); ?>
多デバイス対応
デバイスの判定は、単純にユーザーエージェントを見て行っています。
$pattern = '/' . implode('|', DeviceConfig::$smartphone_useragent) . '/i';
if (preg_match($pattern, $_SERVER['HTTP_USER_AGENT']))
$device = 'sp';
デバイスごとの対応は、根本的に読み込むlayoutファイルやviewファイルなどを変えることで切り替えています。
webrootに、img、js、cssなどのディレクトリが用意されることは多いと思います。多言語・多デバイスに対応するために、その中にもう1階層追加していて、次のような構造になっています。
webroot/ ├─ img/ │ ├─ en/ │ └─ ja/ ├─ css/ │ ├─ pc/ │ └─ sp/ └─ js/ ├─ pc/ └─ sp/
デザインや挙動自体は言語によって変わらないのでcssとjsには言語のディレクトリが不要で、画像はデバイスに応じてviewファイルごと切り替わるのでディレクトリが不要・・・という寸法です。
index.php
WEBのアクセスはwebrootの画像データなどを除いて全て、index.phpに向けられています。そのindex.phpに記述されているのは、インクルードの部分を除いて2行です。
$controller = new Controller();
$controller->View($controller->Action());
batch.php
人気の写真を選出する処理などは、cronで定期的に batch.php を呼ぶことで実行しています。 batch.php はWEBからアクセスできないところに置いて、どの処理を行うかをコマンドラインパラメータで与えます。
set_time_limit(0);
$controller = new Controller('batch');
$result = $controller->Action(array(
'batch',
$argv[1]
));
たとえば、 php batch.php popular とコマンドラインで実行すれば、 http://my365.in/batch/popular を呼び出すのと同じような手順で処理が行われることになります。なんだか面倒くさいような気もしているのですが、フレームワーク内に実装した全ての機能が手軽に使えるので、このようにしています。
おわりに
これで、My365の作り方は終わりです。
作り始めて2ヶ月くらいの頃に「これは一人でプログラムを全部やるのはつらいな・・・」と思ったのですが、途中からヤケになってしまって一人でやってしまいました。(デザイナーの @t_ishiyama がHTMLのマークアップまでしてくれたのはとても助かりました。)
今回3つに分けて要点だけ書きましたが、iPhoneアプリ開発はこの3つのブロックか、サーバ・クライアントの2つのブロックに分けて、2〜3人くらいで開発するととても効率が良いような気がします。
コメント
[…] 投稿ナビゲーション ← 前へ 次へ → […]
[…] My365の作り方 〜サーバサイドプログラム編〜 […]