2015年12月28日月曜日

西友のお墨付きカレー

ちょっと前に西友に置いてあるお墨付きカレーを毎日食べていたので何となくレビュー。
もっと種類があったのですが名前とパッケージで買ったものだけ対象です。


ひよこ豆とやさいのチャナマサラカレー

辛さLEVEL3のインド系豆カレー。豆はヒヨコマメ。辛さはまぁ辛いのを何とか感じますがそんなに辛くないです。後味がちょっと苦味を感じました。火を通しすぎちゃったからかな??次は買わないかも。150円。

カレー辛口

日本系辛口。激辛ってほどでは無いですが食べた中で一番辛く、このくらいで辛いカレーって感じがしました。それでもカレー専門チェーン店で食べるものより空く無いです。刺激が欲しいときはこれにすると思います。一応辛いの苦手な人は避けましょう。値段忘れましたが100円切りました。

カシューナッツ香るマッサマンカレー

インド系(タイ系?)ココナッツカレー。LEVELは3辛ですが、辛さはピリとする程度で完全にココナッツの甘さに負けてます。でもココナッツの香りと甘い風味が旨くて一番食べた。因みにカシューナッツはどこに入ってますか?150円。

バターチキンカレー・キーマカレー

ランチ時にインド料理屋さんに行くと大抵この二つのどちらかを頼みます。私の中で信頼と実績の二大カレーです。 150円でこのクオリティなら勝って良かったと思ってしまいました。そこそこ旨く再現性も中々でした。

カレー中辛

ラストは日本系中辛。辛く無く、辛いのが苦手な人でもいけそうな気はしますが怖い人は試さないほうが良いかと。 パンチも無いのでなんとなくカレーにしたいと思った時には買うかな??こちらも100円切ってたはず。

次のお正月はおせちとお雑煮に飽きたらカレーをたべようかな。

2015年10月9日金曜日

XcodeでGoogle+ iOS SDK が原因で"ERROR ITMS-90535"を発生

自身のiOSアプリの修正をXcode 7.0.1 で行いApp Storeにアップロードしたら以下のようなエラーが発生しました。
ERROR ITMS-90535: "Unexpected CFBundleExecutable Key.The Bundle at 'payload/xxxxxx/GooglePlus.bundle/ GPPCommonSharedResources.bundle' does not contain a bundle executable. If this bundle intentionnally does not contain an executable, consider removing the CFBundleExecutable key from its info.plist. ・・・



何となく翻訳すると
”期待していないCFBundleExecutableキーがある。バンドル実行は許可されない。実行しないならキーをinfo.plistから消して”
という事の模様

でもどうしたら良いか全然わからないのでググってみました。

[SOLVED] ITMS-9000 Error : Unable to submit apps embedding GooglePlus SDK (GooglePlus.bundle)
An important announcement for iOS developers using the GooglePlus SDK

先ず上記二つのページに行きつきまして、
Appleのポリシーが変わったからGoogle+ iOS SDKを1.7.1にバージョンアップしてねって事のようです。
で早速バージョンアップしてみたんですが。。。エラーが解消せず。
バージョンが上がってると思うのに何故か解消されない。

もうちょっと調べてみてstackoverflowに行きつきました。
ここではGoogle+ iOS SDKの中にあるCFBundleExecutableというキーを消せばOKとありました。

XcodeでGoogle.bundleを展開してinfo.plistを開くと「CFBundleExecutable」は見つけられませんでしたが
「Executable file」という変数があったのでこいつを消し。
さらにGoogle.bundleの中にあるGPPCommonSharedResources.bundle、GPPShareboxSharedResources.bundleのinfo.plistからも
同様に「Executable file」という変数を消し。
これで何とかApp Storeへアップロードできました。

アップロードのエラーは解消しましたがアプリはin reviewの状態が続いています。
大丈夫かな。。。

2015年9月21日月曜日

初めての商標権申請

初めての商標権の申請をしてきました。

特許庁の入り口
なかなかかっこいい入り口。

入って直ぐに来庁者受票を記入します。

用件は出願・申請です。
この日は雨でしたが入り口には鍵付きの無料の傘置きもありました。

持ち物検査の後に申請書を出して入館証を貰います。
出願窓口へ向かいますが、場所がわからない場合は場所まで案内してくれます。

窓口まで来て商標権申請書をコピーするのを忘れました。
が、地下一階にコピー機があるのを教えてもらい控え用のコピーをしてから望みました。
窓口の手前で特許印紙を販売しているので購入します。
併せて、申請書を電子化する為の料金も払えるので払いたい人は払います。ここで払わない場合は後日ハガキが 送付されるようです。
私はめんどくさいので払いました。

手続きはすんなり終わり控えにハンコをしてもらいました。

あとは数か月後に無事審査が通るのを待つばかりです。楽しみ。


申請書の書き方やフォーマットはインターネットで結構集められるのでここでは触れません。
申請したい商標が既に申請や登録されているのか?自分の申請したい区分がどこにするべきなのかは
自分で出来ない事も無いけど専門家(弁理士さん)へ相談する方が賢明だと思いました。
折角申請しても既に申請済みだったり、検討違いの区分に申請したり穴があったりしたら勿体ない。
今回相談させていただく機会があったので本当に助かりました。

普段特許庁とか行かないのですごい新鮮だった

2015年8月29日土曜日

EGitのインストールで署名付きコンテンツの読み取り中にエラー

Eclipse(4.4.0)にEGit(4.0.1.201506240215-r)を入れようとしたらちょっと躓きました。
以下のエラーが発生してEGitをインストールが出来ない状態が発生してしまいました。

An error occurred during the org.eclipse.equinox.internal.p2.engine.phases.CheckTrust phase. session context was:(profile=epp.package.standard, phase=org.eclipse.equinox.internal.p2.engine.phases.CheckTrust, operand=, action=). Error reading signed content. error in opening zip file

zipファイルを開く時に署名付きコンテンツの読み取り中にエラーが発生したって事らしいです。

日本語の解決策がいまいち無かったのでおなじみstackoverflowを参考にさせてもらいました。
ここを読ませていただく限り
Eclipse の root ディレクトリにある artifacts.xml を消せ
って事のようです。
早速試してみたら解決しました。

ただ、懸念点として前述のxmlファイルはEclipseがプラグインを管理するライブラリの一部らしいです。
私の現在の環境は影響がありませんが、場合によってはどこかに影響が出る可能性はあるかもしれません。

2015年8月13日木曜日

青色申告の勉強

今年から個人事業主として活動している中でいまいち複式簿記のやり方がわからないので
色々と探してみた結果、練馬区(住んでる街)で練馬区青色申告会というのが存在してそこで
複式簿記の講習を無料でしてくれているとの事で参加してきました。

地域(おそらく)によって種類は数は異なりますが複数の講習の種類があるようです。
参加できる条件は詳しく確認してませんが問い合わせたら私はどれか一つに一度だけ
参加して良いらしいです。

私はPCソフトを使用した『会計ソフト 「ツカエル青色申告」 講習会』に参加してきました。
初日は2コマで最初に青色申告の概要的な話、ソフトの起動と簡単な入力練習をやりました。
2日は結構間が空いてやってくれるそうです。

講習はあっというまでしたが、質問タイムもありだいぶ勉強になりました。
こういう講習をやってもらえると大変助かります。

因みに講習で配られた資料。
緑のやさしい複式簿記は巻末資料や減価償却資産の償却率表は今後もお世話になりそうな予感がします。

で、ここで推薦している会計ソフト「ツカエル青色申告」

ツカエル青色申告 +確定申告 15 新消費税対応 乗換・優待版

触った感じはまぁ使えて便利そう。ただライセンスは毎年払わないといけない。 そりゃそうだろうけど思わず言ってしまう。

2015年5月8日金曜日

Phalcon 2.0 がリリース

もう2週間経ってしまいましたがPhalconから2.0がリリースされたアナウンスがありました。
取り留めも無くざっくり所感を。

Phalconのブログを読むと
  • Zephir で作りました
  • 1.3.xの関数はそのまま書き換えているからアップグレードをオススメ
  • Zephir だから今まで以上に皆さんに機能を提供できますよ
  • みんなありがとう!

Zephir で作った事が非常に強調されています。

用意されているVimemoを観た感じではファイルの自動生成系は 充実しているようです。私は余り自動生成に頼らないんですが喜ばれる方は多いはず。

1.3.xの関数がそのまま使えるというので単純に置き換えるのは簡単そう。ただ根っこが変更されているならば テストは細かくやらないと不安に思ってしまいます。
個人的には必要に迫られない限り1.3.x -> 2.0 は避けると思います。 新しくやるならば 2.0 を選びます。

チュートリアルのMVC回りを読んだ限りでは表面的なスキーマに大きな変更点は無く、私が勝手に期待した サブモジュールの実装は無いみたいです。

処理速度が気になるが、それはそのうちテストしてみようかと。

リリースされたばかりなのでこれからの動きに注目したいと思います。

2015年3月10日火曜日

PhalconとPostgresqlとバイナリーデータ

Phalconを使いPostgresqlのbytea(バイナリー)型へ画像の登録をしてみた。 ちょっと気を付けなければならないと思いメモする事に。
最初にポイントだけ書くとModelを使用した場合に登録、更新時のデータ型と取得した時のデータ型が異なって いるので気を付けなければいけない。また、基本的にはその部分について書いているので他の点についてはだいぶ 簡略化して記述している。

併せて、これを実行した時の各種バージョン
Postgresql 8.4.X
PHP 5.5.15
Phalcon 1.3.2

今回は以下のようなsqlで作成されたbytea型を持ったテーブルから画像データを操作するイメージで 考える。
create table t_image (
  id bigserial not null
  , file_name varchar(255)
  , binarydata bytea
  , constraint t_image_PKC primary key (id)
) ;

上記のテーブルを前提とした場合 model は以下のようになる。 Image.php
class Image extends \Phalcon\MVC\Model
{
  public $id;
  public $file_name;
  public $binarydata;

  /**
   * ソース指定
   *
   * @see Phalcon\Mvc\Model::getSource
   */
  public function getSource()
  {
    return "t_image";
  }
}

画像の登録

Phalconで送信されたファイルを受け取る方法はPhalconのドキュメントを参照する。 参照したデータからバイナリデータを読み出し16進数文字列に変換して登録する
$image = new \App\Mvc\Model\Image();
if ($this->request->hasFiles() == true) {
  // test.png というファイルが送信されると仮定した実装
  foreach ($this->request->getUploadedFiles() as $_file){
    if($_file->getName() == "test.png"){
      $file = $_file;
    }
  }
}

// ファイルがあれば登録を行う
if($file){
  $image->file_name = $file->getName();
  $image->binarydata = bin2hex(file_get_contents($file->getTempName()));
  $image->create();
}

画像の表示

Phalconのモデルを使用した場合にはbytea型にはリソース型が設定される 以下実行例
$image = \App\Mvc\Model\Image::findFirst(array(
    "conditions" => "id = ?1",
    "bind"         => array(1 => 1),
  )
);
if($image && $image->binarydata){
  var_dump($image->binarydata);
}

-- 標準出力 -------------------
resource(21) of type (stream) 
出力する際にはリソースの中身は16進数文字列なのでバイナリ文字列に 変換してから出力する
if($image && $image->binarydata){
  header('Content-Type: image/png');
  echo hex2bin(stream_get_contents($image->binarydata));
}

更新時の注意点

画像の表示で触れたModelを使用した場合にはbytea型にはリソース型が設定される事により bytea型はリソース型から一度文字列データへ変換しないとデータが失われてしまう。
$image = \App\Mvc\Model\Image::findfirst(array(
    "conditions" => "id = ?1",
    "bind"         => array(1 => 1),
  )
);

// ファイル名だけ変更
$image->file_name = "othername.png";

if($image->binarydata){
  // リソースから文字列データを抜出し再設定。
  // リソース型を自動で登録するような事はしてくれていない
  $image->binarydata = stream_get_contents($image->binarydata);
}
$image->update();
勢いで書いてしまっているのでだいぶ端折っているがポイントは網羅できていると思う。 Model::findfirst()で取得してModel::update()やsave()で更新させるのは Phalconでは結構重要な思想のはずだが、データ型が違うという事を意識しなければならないのは ちょっと厳しい。。。もしくはもっと簡単に行う方法があるのかもしれない。

2015年1月31日土曜日

最近のバイクアイテム

今シーズンのマイ・ベストバイ2品。

■RIDEZ Waterproof Case Sサイズ
サイズ展開は数種類ありますが自分はiPhone 4SなのでSサイズです。

RIDEZ(ライズ) Waterproof Caseウォータープルーフケース スマートフォンホルダー Sサイズ 4527625088801
最近ツーリング時に道を間違える事が多いのでナビを導入したいと思うようになってきました。 本当はTabletをナビにしたいと検討していたけどスマートフォン用がリーズナブルだったのでこっちにしました。 iPhoneをナビとして何度か使用してますが安定していて落ちそうになったり等は全くありませんでした。 ホールドはしっかりしているようで安心して使えます。 ケースの上からでも画面を操作できるのも○。色々とはかどります。 因みに自分だけかもしれませんが、最初にホルダーとケースを結合させる時に感触がわからず 不良品だと思ってしまいました。 店員さんにお願いしたら結合しましたが、諦めずに思いっきり結合させる必要有りです。


■SWAT ミリタリーブーツ

SWAT S.W.A.T サイドジッパー ミリタリーブーツ ジャングルブーツ タクティカルブーツ 黒色 ブラック 黒 28.0cm

S.W.A.Tミリタリーブーツのレプリカ(?)。 バイク用のブーツが欲しいが大体1万~ですがこいつは4300円で買えたのでコストパフォーマンスは最高です。 自分の足は27cmなのですが28cmを買ってホッカイロが入るようにしています。 だいぶイメージ通りですがちょっと安っぽいのと足先が分厚い為にクラッチの下に足を入れるのがちょっと辛いです。 足首がだいぶ伸縮するのでクラッチ操作は十分できます。

2014年12月24日水曜日

象本とHadoop MapReduce デザインパターン

Hadoop

Hadoopの導入から基本的なシステムの解説、サンプルコードなどが書いてあった。
javaやlinuxの知識がある程度あれば読むには困らない。と思う。
試しにシステムを構築して実行するまではこれでいける。
私が買ったのは第二版でHadoopを前提にしたPig、Hiveなど
にも触れてくれているのでかなりお得な一冊でした。

私が読んだのは第二版だけれでもすでに第三版が出版され大幅加筆されているとか。

Hadoop 第3版


Hadoop MapReduce デザインパターン

読み終えて、いや途中から内容が高度すぎて今はついていけなかった。。。
この本を完全に理解するには数学、統計学の知識が必要な為、勉強して読み直さないとならない。
単純な集計処理であればこの本を読まずとも前述の本で間に合うと思うが、
高度で専門的な統計業務をするのであればこっちの本の内容が助けになりそう。

Hadoop MapReduce デザインパターン ―MapReduceによる大規模テキストデータ処理



Hadoopに限らず大規模データ分散処理システムは設計、構築、運用も非常にコストがかかる
ものなので今のところ読むに留まる内容であった。

2014年12月2日火曜日

Looking for Lost for TM 反省会

アプリ「Looking for Lost For TM」の開発にはPhonegapを使用しました。
Google Play用、iOS用のどちらも一つのコードで作れると言うのはとても魅力的に感じたので採用しました。
今回は反省会として所感を一回まとめておく事にします。
因みにPhonegapのバージョンは 3.6.0-0.21.29 です。

Google Play アプリ名文字列長制限
Google Play アプリを登録する際にはアプリ名が30バイト以内で無いといけない。
そんなことはお構いなしで「Looking for Lost on the Tokyo Metro」とか名付けたら名前を変更しなければならなくなってしまった。
各種制限については良く確認しておく事。基本です。

誤解の無いアプリ名を付ける
またアプリ名称について。
最初は

 Looking for Lost on the Tokyo Metro

でしたが、最終的には

 Looking for Lost for TM

になった。
iOS用アプリを登録する際にAppleの審査でアプリ名について「on ○○」っておかしいだろ?
といった内容の指摘を受けました。個人的には東京メトロ路線上で使用するという意味を込めた
つもりでしたがそんな説明するのはめんどくさく、かつ、誤解されても困るというのは共感できる
ので名称を変えました。
また、Google Play アプリの文字列制限もクリアする為に the Tokyo Metro も TM へ省略してみました。

Phonegap:アプリ名に日本語名がつけられない
私の技術力の限界でもありましたが、そもそもアプリ名がちとダサいのはPhonegapではアプリ名に
日本語を付けるのが私にできなかった為です。
ネットを検索すると何とか日本語名をつけた方もいらっしゃるようですが、私は断念しました。

Phonegap:remote build と local build で出来上がるものが違う
致命的では無いけれども、 remote build と local build で生成されたファイルに違いがある。
phonegap では project を生成するとwww/resというディレクトリが作成され、そこにsplah用の画像やアイコン画像などを入れられるのだけれども、 remote build では入れたファイルが使われるのだけれども local build では全く使われない。
build の方法によって変わってしまうとなると折角一元管理を目指していたのにめんどくさい
事になってしまった。

Phonegap:iOS用ファイルにプラグインが出力されない
今回はphonegapが提供している追加のプラグインを使用していますが、
iOS用のファイルをリリースする為に local build したものをXcodeで開いたらpluginファイルが
ありませんでした。(remote builde は未確認)
phonegapのgithubから直接ファイルをダウンロードしてきてXcode上でファイルを自分で追加する羽目になり、結構悩んだ。ここはどうにかして欲しい。


コード自体はHTMLとjavascriptなので概ねGoogle Play用、iOS用に対して共通のコードで開発できました。
ただ、画像等のリソース管理、コンパイルやストアへのアップロード等でそれぞれ別の問題に突き当たるのは避けられなかった。まぁ避けられないのは仕方の無いことだろうか。
いやーな事が結構書いてますが、あまり複雑な事はしていない場合に日本語名とpluginが出力されないのを我慢できれば Phonegap の採用はありかな。



2014年11月3日月曜日

Looking for Lost on the Tokyo Metro

2015/11/14にこのアプリの公開を停止しました。

現在はこのアプリはご利用いただけません
Looking for Lost on the Tokyo Metroというアプリを開発しました。
この記事はLooking for Lost on the Tokyo Metroというアプリの告知兼サポートページになります。
またこのアプリは東京メトロアプリコンテストへ応募する予定です。

 
これは東京メトロAPIの列車ロケーション情報を使用した電車内に置き忘れた物を探すアプリです。
忘れ物をした時の情報を入力する事により忘れ物をした車両の位置をリアルタイムで探します。
駅係員の方や鉄道会社の遺失物担当者の方へ状況を伝える場合などにご利用ください。
 


使い方

使い方はとっとも簡単です。忘れ物に気付いた際に入力画面で乗降者した列車の沿線、駅名、進行方向、時間を入力 して探すボタンを押すだけです。サーバーへ列車を問い合わせし結果画面へ該当する列車があれば列車の情報が表示 されます。表示された内容をもとに駅係員様へお問い合わせください。

Movie


スクリーンショット




 

2014年10月24日金曜日

PhalconのDB\AdapterをDIへ登録する際の注意点

今まで勘違いしていたので覚えて置く為のメモ。

PhalconでDIへDb\Adapterを登録してtransactionを一元管理するのはできないのだと思っていたら 使い方が間違っていた。
DIへ登録する時にはshared(共有)として登録すれば呼び出し先で同じコネクションのインスタンス を使用してくれる。逆を言うとsharedしないと同じインスタンスを使用してくれないようだ。
具体的には
// 第三引数にtrueを指定
$di->set('db', function() use ($config) {
    return new \Phalcon\Db\Adapter\Pdo\Postgresql(
    $config->database->toArray());
}, true);
本当にトランザクションが制御できているか以下の方法で確認
DBにテーブルを用意する
CREATE TABLE name1 (
  id SERIAL PRIMARY KEY,
  name text
);
テスト登録用処理を実装したモデルクラスを用意する。
class Name1 extends \Phalcon\MVC\Model
{

    public $id;
    public $name;

    public function getSource()
    {
        return "name1";
    }

    /**
      * 引数のコネクションと関数内で生成したコネクション
      * でそれぞれ登録
      *
      */
    public static function insertTest($src_db){
        $name = new \App\Mvc\Model\Name1();
        $db = $name->getDI()->get("db");
        for($i=0;$i<5;$i++){
            $name = new \App\Mvc\Model\Name1();
            $name->name = 'FFFFF' . sprintf("%05d", $i);
            $name->create();
            $result = $db->query("INSERT INTO name1(name) VALUES(
                '" . "DDDDD" . sprintf("%05d", $i) . "')");
            $resulta = $src_db->query("INSERT INTO name1(name) VALUES(
                '" . "EEEEE" . sprintf("%05d", $i) . "')");

        }
    }
}
DIのsharedをtrueにしたものとしないものの両方で以下の処理を実行する。
具体的にはコントローラー、生成したモデルのテスト用関数で登録処理が行われ、例外を意図的に 発生させてrollbackを行う。
try{
   
    $this->db->begin();
    for($i=0;$i<5;$i++){
        $name = new \App\Mvc\Model\Name1();
        $name->name = 'AAAAAA' . sprintf("%05d", $i);
        $name->create();
                
        $result = $this->db->query("INSERT INTO name1(name) VALUES(
            '" . "BBBBB" . sprintf("%05d", $i) . "')");
    }
    \App\Mvc\Model\Name1::insertTest($this->db);
            
    throw new \Exception("trnsaction test");
    $this->db->commit();
}catch(Exception $e){
    if($this->db->isUnderTransaction()){
        $this->db->rollback();
    }
    throw $e;
}

sharedした場合の結果は
test=# select * from name1;
 id | name 
----+------
(0 行)

しなかった場合、インスタンスを別で取得して登録した分が残ってしまう。
test=# select * from name1;
 id |    name    
----+------------
 12 | DDDDD00000
 15 | DDDDD00001
 18 | DDDDD00002
 21 | DDDDD00003
 24 | DDDDD00004
(5 行)
一元管理したい場合はsharedをする事で可能になる。一番起きそうなのは一元管理するつもりだったのに sharedしないで登録してしまいtransactionがめちゃくちゃになってしまったという事故。

connectionのインスタンスはDB回りのクラスで管理されるものと思い込んでいたのでDIでやる発想が無かった。 こんな方法もあるんだな。

2014年10月14日火曜日

Google Play アプリ開発で参考にした本

Google Play版のPocket Trumpetterも無事リリースに至りました。

アプリ開発ではもはや名著「初めてのAndroid 第3版」を参考にしています。

初めてのAndroid 第3版

javaの基本的な知識は必要ですが、シンプルなアプリの開発ならこの本の例を作る過程で身につく
と思います(少なくとも私は身についたと思っています)。
強いて惜しいと思われるのは、内容はちょっと古いんじゃないかと思っています。
サンプルで使用されたライブラリや関数が非推奨になっていたり、Fragmentについては触れられなか
ったりと。まぁこんなものは大したマイナスではないと思いますが。

2014年8月31日日曜日

Phalconで強引なSubmodule

ここ最近、自称最速PHPフレームワークを謳っているphalconというのを
使っています。早い根拠はコアな部分をC言語で実装している為だそうです。
(SQLをログに出力すると意図しないクエリーをDBに流しているように見受けられ、遅くならないか? と心配になるが今回の趣旨とは異なるのでこれ以上触れません)

Laravelもチラ見したたけれども、最近のフレームワークはmoduleというくくりがちょっと 大きい単位になってしまっている気がしていまいち自分の意図と合わない。
個人的には関連するcontrollerやviewなどをある程度纏めた単位をsubmoduleとした構成にしたい。
かなり強引だけどnamespaceを使って実現してみる事に。
phalconのインストールからmodule構成まではphalconの公式ページを探せば見つかるので これまたここでは触れません。

先ずファイル構成はこんな感じ

├─app
│  ├─config
│  │      config.ini
│  │      loader.php
│  │      module.php
│  │      service.php                        # route処理を定義。
│  │                                         # ここでURLとmodule、name
│  │                                         # space、controller、acti
│  │                                         # onを関連付け
│  │
│  ├─frontend                               # frontend module
│  │  │  Module.php
│  │  │
│  │  ├─modules
│  │  │  ├─error                          # エラー処理用 submodule 
│  │  │  │  │                             # コントローラーのnamesp
│  │  │  │  │                             # aceは error
│  │  │  │  ├─controllers
│  │  │  │  │      IndexController.php
│  │  │  │  │      
│  │  │  │  ├─forms
│  │  │  │  └─views
│  │  │  │      └─index
│  │  │  │              app.volt
│  │  │  │              notfound.volt
│  │  │  │              system.volt
│  │  │  │              
│  │  │  └─index                          # index処理 submodule 
│  │  │      │                             # コントローラーのnam
│  │  │      │                             # espaceは index
│  │  │      ├─controllers
│  │  │      │      IndexController.php
│  │  │      │      
│  │  │      ├─forms
│  │  │      │      IndexForms.php
│  │  │      │      
│  │  │      ├─language
│  │  │      │  └─exprss
│  │  │      │          ja.php
│  │  │      │          
│  │  │      └─views                      # index module 専用のテ
│  │  │          │                         # ンプレートをここに作
│  │  │          │                         # 成する。
│  │  │          └─index
│  │  │                  index.volt
│  │  │                  
│  │  └─views
│  │      │  base.volt                      # 共通template
│  │      │  
│  │      └─layouts
│  │              main.volt                  # 共通layout
│  │              
│  ├─library
│  │  └─mvc
│  │          Module.php                     # module用親クラス。sab
│  │                                         # moduleのロード等
│  ├─logs
│  └─plugins
│          
├─cache
└─public
        .htaccess
        index.php
            

}}}
[config/service.php] phalconを実装する多くの場合でdependency injectionの各serviceをここで 定義していると思う。 ここでsubmodule構成の為にrouterサービスを定義。
/**
 * Specify routes for modules
 */
$di->set('router', function () {

    $router = new \Phalcon\Mvc\Router();

    // デフォルトモジュールを frontend に設定
    $router->setDefaultModule("frontend");

    /* frontend/modulesの直下にあるディレクトリ名をnamespaceとして定義
       ここで/foo/var/indexとアクセスがあった場合、以下が設定される
       module     = frontend
       namespace  = foo/Controllers
       controller = var
       action     = index
     */
    $modulesDir = APP_ROOT_PATH . DIRECTORY_SEPARATOR . 'frontend/modules';
    $dir = @opendir($modulesDir);
    if($dir){
        while($dir_name = readdir($dir)){
            // exclude [.],[..],[*.php]
            if($dir_name == '.' || $dir_name == '..'
               || strpos($dir_name, ".php") > -1){
                continue;
            }
            $router->add("/" . $dir_name . "/:controller/:action", array(
                    'module'     => 'frontend',
                    'namespace' => $dir_name . '\Controllers',
                    'controller' => 1,
                    'action' => 2,
            ));
        }
    }

    return $router;
});
もしModuleがfrontend以外にもあるのならそのディレクトリも同じように登録すれば 実現可能。


[library/mvc/Module.php] ここでは特に2つの事を行う。

1つはmodules直下を読み込んでいってnamespaceとしてロードする
    /**
     * Register a specific autoloader for the module
     */
    public function registerAutoloaders()
    {

        $loader = new \Phalcon\Loader();

        $namespaces = array();

        $modulesDir = APP_ROOT_PATH . DIRECTORY_SEPARATOR . 
                        $this->module_name .  '/modules';
        $dir = @opendir($modulesDir);
        if($dir){
            while($dir_name = readdir($dir)){
                // exclude [.],[..],[*.php]
                if($dir_name == '.' || $dir_name == '..'
                  || strpos($dir_name, ".php") > -1){
                    continue;
                }
                $namespaces[$dir_name . '\Controllers'] = $modulesDir . 
                   DIRECTORY_SEPARATOR . $dir_name . DIRECTORY_SEPARATOR .
                   'controllers';
                $namespaces[$dir_name . '\Forms'] = $modulesDir . 
                   DIRECTORY_SEPARATOR . $dir_name . DIRECTORY_SEPARATOR .
                   'forms';
            }
        }
        
        $loader->registerNamespaces($namespaces);
        
        $loader->register();
    }
公式サイトにもModuleのautoloadersの実装方法があるが、少し変化させて今回の目的に対応できるようにした。
modulesの直下にあるnamespace用ディレクトリの直下にcontrollersとformsというディレクトリを用意して、 それぞれnamespaceとして定義してローダーに登録している。
modules/indexを例にすると以下のようになる
  └─index
      ├─controllers                # namespaceはindex\Controllers
      │      IndexController.php    
      │      
      ├─forms                      # namespaceはindex\Forms
      │      IndexForms.php
      │      
他にこのnamespaceの単位に組み込みたいものがあれば(modelを追加したい場合はあるかもしれない) ここで定義すれば追加可能。

2つ目はviewの定義。各ファイルはnamespaceを使う方法に依って相互に認識しあえるようにできたが、 viewがちょっと異なる。controllerなどのphpファイルはnamespaceが利用できたが、viewのテンプレートは PHPのクラスで無い為にnamespaceに頼る事が出来ない。
(他の多くのフレームワークでもそうだと思うがテンプレートは通常のファイルとして扱っている)

Moduleでserviceを登録できる方法が提供されているので、viewをここで定義する。
レイアウトとメインのテンプレートは共通のディレクトリを使い、各アクションに依存した画面テンプレートは modules以下を使うようにしたい。

    public function registerServices($di)
    {
        $module_name = $this->module_name;

        //Registering the view component
        $di->set('view', function() use ($di, $module_name){
            $config = $di->get("conf");
            $view = new \Phalcon\Mvc\View();
            $view->setViewsDir(APP_ROOT_PATH . DIRECTORY_SEPARATOR . 
               $module_name . $config->application->viewsDir);

            // レイアウトディレクトリとメインは共通のディレクトリを示
            // すように定義
            $view->setLayoutsDir('../../../views/layouts/');
            $view->setMainView('../../../views/base');
            
            $view->registerEngines(array(
                    ".volt" => 'volt'
            ));

            // change view directory by namespace
            $eventsManager = new \Phalcon\Events\Manager();
            $eventsManager->attach('view', function($event, $view)
               use($module_name) {
                $dispatcher = $view->getDI()->getShared("dispatcher");
                $nName = $dispatcher->getNamespaceName()
                if ('beforeRender' == $event->getType()) {
                    // レンダリング前にviewのディレクトリを
                    // modules/namespace/views になるように設定。
                    $view->setViewsDir(APP_ROOT_PATH . DIRECTORY_SEPARATOR . 
                      $module_name . DIRECTORY_SEPARATOR . 'modules' . 
                      DIRECTORY_SEPARATOR . substr($nName, 0, 
                      strpos($nName, '\\', 0)) . DIRECTORY_SEPARATOR . 
                      'views' . DIRECTORY_SEPARATOR
                    );
                }
            });
            $view->setEventsManager($eventsManager);
            
            return $view;
            
        });

        $di->set('volt', function($view, $di) use ($module_name) {
        
                    $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
                
                    $volt->setOptions(array(
                            "compiledPath" => APP_ROOT_PATH
                               . "/../cache/volt/" . $module_name
                               . DIRECTORY_SEPARATOR
                    ));
            return $volt;
        }, true);
            
    }



[frontend/modules/index/IndexController.php]
/index/index/indexでアクセスされた場合にrouterによって紐付けされるように実装する。 注意する点はnamespace。routerとModuleで定義した内容とマッチするように定義する
namespace index\Controllers;

class IndexController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {
    }
}


どうしてこうなったのか?

色々考えた結果、phalconのフローの関係で今回挙げた処理は前述の箇所となっり、このスタイルに 落ち着いた。デフォルトのModuleの単位をこのレベルに引き落とす方法も見当したが、エラーハンド リングがどうしても共通で行う方法にしっくりくる物が無かった。
routerの定義、namespaceの登録とロードはdispatchがされる前で、viewサービスはdispatch後に実行 されるようなのであのような形になった。


もっと良い実装方法 or 実はphalconの機能で実現する方法が存在するかもしれない。
今のところはこんな方法だろうか。

2014年8月22日金曜日

PHP5.3系のEOL

PHP5.3系が2014/08/15にリリースされた5.3.29をもってEOL(End of Life)と宣言されました。
今後の5.3系でリリースは予定されていないそうです。
またすみやかな 5.4 o r5.5 への移行が推奨されています。

php.netを読み返してみると2009/06/30に5.3.0がリリースされてからおよそ5年が経過していました。 なんかしみじみするなぁ。

詳しくはphp.netのアナウンスにて。

2014年7月25日金曜日

IPhoneアプリ開発で参考にした本

Pocket Trumpetterに参考にした本。
そもそもPHPを中心としたWEBシステムの開発者なので IPhoneアプリの作成は門外漢。作ろうにも何の知識も経験 も無いので効率良く作る為に2冊の本を参考にした。

[iPhoneアプリをプロデュースiOS SDK 5]

iPhoneアプリをプロデュース iOS SDK5 (SCC Books)

アプリ開発の為の全体の流れをこの本で把握した。WEBシステムの開発であれば 多くのケースでMVCモデルを採用しているので実際に処理をするプログラムや、 画面表示用のプログラム等をどう用意すれば良いのかイメージが湧くのだけれども、 アプリ開発ではイメージがわかないので、イメージが湧くような入門書を読みたいと 思っていた。これは正にBING。
サンプルプログラムが書いてあるので、環境を整えてそのまま実装すれば大体動く物 ができあがる。
他言語の経験があればこれで大体流れがわかると思う。ただし、経験が無い場合は何を やっているかわからない内にアプリが出来上がってしまうと思う。


[Objective-Cの絵本 (絵本シリーズ) ]

Objective-Cの絵本

1冊目はアプリ開発の流れを知りたくて読んだが、Objective-Cについては全く知らないので 補助的に読んでおいた、基本はCなのでポインタなどの概念があったりする。PHPのポインタ とはだいぶ違うと思い読んでおいた。また、1冊目では理解できない(受け入れ難い)関数の 宣言方法など色々と「くせ」の違いもわかってモヤモヤが減ったので読んでよかったと思う

本当はもっと深い点に触れた本を読む必要があると思っているがPocket Trumpetterは そんなに複雑な事は行わないので、一先ず絵の多い薄めの入門書2冊に留めている。 また入門書とは言えど、ある程度の経験が無いと意味不明なままになるんじゃないかとはちょっと 思う。(これより簡単なものがあるかはわからない。 今後、本気でアプリ開発をする場合はポインターやメモリ管理について勉強して おくべきかと思う。

2014年7月13日日曜日

Pocket Trumpetter

I developed Pocket Trumpetter.
This Page is Announcement and suport for Pocket Trumpetter.

Pocket Trumpetterというアプリを開発しました。
この記事はPocket Trumpetterというアプリの告知兼サポートページになります。

 
 
This App is Trumpet Simulator. If you touch any embouchure button and three piston button, move trumpetter's finger and make sound. You are permitted playing trumpet at the limited place, but you can play this anytime and anywhere use earphone.
Let's Try!
これはトランペットシミュレーターアプリです。ボタンを押すとトランペッターの指が動いて押したボタンに対応した音がでます。トランペットは演奏する場所が限られますが、このアプリならばいつでもどこでも遊べます。
是非お試しください!
 


Screenshot




 

Movie