気持ちよさそう!温泉その2。趣あってイイ!温泉その3。21日目担当のMASA-Pです。CakePHP界隈ではいろいろとやらせていただいていますが、PHPコミュニティの方はなかなか日程等があわない関係もあって不参加状態ですので、もしかしたら初めましての方もいらっしゃるかもしれません。一応こんなものなんかを公開させていただいております。こんな本とかこんな本なんかを執筆させていただだいておりますので、もし興味がありましたら是非よろしくお願いします。Tipsという事なのですが、非常にお恥ずかしい話ですが当方は既にCakePHPがないと生きていけない体になっております(笑)。当方としましてもそういう道連れ的な方を一人でも多く製造したい次第ですので(笑)、布教活動がてら「CakePHPに存在している超便利な機能をライブラリとして使ってしまおう!」ということで記事を書いてみたいと思います。実例としては前日のomoonさんの記事とネタが被っているかもしれませんが、まあ続編と思ってもらっても全然構いませんです(^^;。CakePHPのフレームワークの機能についてここで多くを語るのはやめるとして、CakePHP内には「便利クラス」なるものがいくつか存在します。一押しなのが、今回取り上げさせていただく「Setクラス」です。このクラスは、配列の操作をより便利にする機能を持っています。PHPは標準でも他の言語と比べて配列を自在に操れる方だとは思いますが、かゆいところに手が届かないものもいくつかあります。このSetクラスを使うと、その辺が簡単に解決できたりする場合があります。CakePHP辞典」を参照してください。今回はこの中のSet::extract()とSet::combine()を動作サンプルとして掲載します。前置きはこのくらいにして、さっそくピュアPHPコード内でCakePHPのコードを使用する方法をご紹介しましょう。1:CakePHPのコードを配置する先でも後でも良いのですが、とりあえずCakePHPコードを配置してしまう事にします。今回は、ドキュメントルート内に利用元のピュアPHPコードを展開し、「includes/」内に利用したいCakePHPコードのファイルのみをを入れます。ドキュメントルートとは別の一にCakeのパッケージを丸ごとインストールして、そこを参照したりしても良いかもしれません。CakePHPはこちらからアーカイブを入手し、その中の「cake/libs/set.php」をincludesにコピーします。Setクラス内では同じくCakePHPライブラリである「Stringクラス」も呼び出していますので、「cake/libs/string.php」もコピーします。その他にもクラスを呼び出しているものがありますがそれは次のステップで。2:ダミークラスを作成するCakePHPのコードを使うための、超最低限の機能(?)を有するコードを作成します。includes内に「cake.php」ファイルを作成します。内容は次のようにします。$class){include(dirname(__FILE__).DS.strtolower($class).'.php');}}Objectクラスは、CakePHPのほとんどのクラスが継承している基底クラスで、ライブラリでも使用している場合があります。ダミークラスを作成して問題を起きにくくしておきます。App::import()はCakePHP内で自在にincludeするための便利メソッドで、これもライブラリ内で用いられています。SetクラスでもStringクラスを呼び出すために使用しています。本来は$typeでクラスの種類(ControllerとかModelとか)を指定するのですが、今回の実装ではincludesディレクトリに全て突っ込んでしまうため、無視します。$classはupperキャメルケースで表現されていますのでアンダースコア形式に変換する必要がありますが、今回はインチキしてstrtolower()してしまっています。厳密にやるのなら「cake/libs/inflector.php」内のメソッドを用いるとできると思います。最後に目的のコードを記述します。今回は次のようなコードで実験する事にします。'{n}.UserProfile.name');var_dump($arr);実行結果は次のようになります。}SetクラスはCakePHPユーザでもあまり使われていないかもしれないのですが、この便利さは魔力を秘めているというのか使い出したら止まりません(^^;。上記2つはデータベーステーブルから特定の値を抜き出したりする場合に威力を発揮すると思います。今回触れてはいませんが、Set::merge()やSet::sort()なんかもかなり便利です。array_merge()は1次元目の配列要素に対してのみマージが行われますが、これは多階層の配列に対して再帰的にマージが可能です。sortについても、特定のパスの値に対してソートをかける事ができるので、例えばとりあえず取ってきた複数レコードのデータをid順に並べ直したりといったことが簡単にできます。Setクラスは少々CPU%を使う仕組みだと思うので、peclかなんかでモジュールを利用する形で作ったりすると良いのかもしれませんね。いや、できればPHPで標準化されて欲しいものばかり!(笑)ぱっと見なのですが、Setクラスだけでなく次のクラスライブラリもたぶん同様の方法で使えると思います。したりキャメルケース←→アンダースコアに変換したりできるクラスStringクラスUUIDを生成したり、テンプレート文字列に要素を挿入したりできる機能のあるクラスNumberHelperクラス通貨など数値関連のフォーマッティングをしてくれるクラス。AppHelperクラスを上記のObjectクラスのようにダミー化する必要がありますTImeHelperクラス時間に関するフォーマッティングをしてくれるクラス。strtotime()等の機能をより便利に拡張します他のクラスにも有用なものがありますが、ちょっと大がかりな工夫をする必要がありそうなので、興味があったらチャレンジしてみてください(Validationクラスくらいなら比較的簡単にけるかもしれない)。アマゾンのサーバでエラーが起こっているかもしれません。一度ページを再読み込みしてみてください。当番が回ってきました。本来はもっとかる~い内容でいくつもりでしたが、皆さんがっつりとやられているので、慌てて秘蔵のネタ(?)を引っ張り出すことにしました。まあとはいえ実際はそんなでもないので軽く読んでいただければ(笑)。Modelにまつわる話が多いようなので今回も違う話題にしましょう。Modelは今までTipsが出にくい仕組みの一つだったのかもしれないのですが、同じくなかなか情報として出回らないRoutes関連でも取り上げてみようと思います。取り上げられていましたが、CakeぽくないURLを作成するためにはRouteを変更することで自由なURLにコントローラとアクションを振り分けることができます。多くの場合「/:controller/:action/*」という標準のルート指定で問題がないため、修正する機会はなかなかないのではないかと思います。そこで2ステップでRoutes活用法をご紹介します。ステップ1:パラメータチェックをRoutesで済ませてしまうRoutesの設定は上記のようにURL変更というのも活用法のひとつかもしれませんが、もう一つとても便利な使い方があります。それは、URL中にパラメータを含む場合に、そのパラメータチェックをRoutes内で行うことができる点です。http://www.example.com/foo/hoge/0123456789というURLを想定するとしましょう。fooコントローラ内のhogeアクションで1つの値を入手したい場合です。この場合、デフォルトですとコントローラ内の「$this->params[‘pass’][‘0’]」に値が入ります。そこで一般的に、次のようなコントローラを書くでしょう。'/');return;}//以下、必要な処理//}}しかし、Routesを活用することで、コントローラにチェックを書かずにチェックを行うことができます。「app/config/routes.php」に次のように記述します。'error'));この場合は$this->params[‘viewerId’]にて値を受け取ることができます。条件に満たさない「/foo/hoge」はすべてerrorアクションに流れます。Router::connect()は先着順でルーティングを決定しますので、一番最後に条件を満たさない場合のルートを書いておけば、デフォルトである「/:controller/:action/*」に流れることはありません。controllerのスリム化に貢献できると思います。不要なアクションがコントローラ内に渡ってこない点にあります。そもそもURLから渡されるパラメータはコントローラに渡ってくる時点で正しいものであるべきかと思いますので、Routesでチェックすることは理にかなっていると言えます。ステップ2:正規表現で表せないルーティングはどうするか?上記ルーティングは、あくまでも正規表現で表される場合であり、複雑な条件分岐を伴ったりモデルを参照したい場合などはうまく表現できません。CakePHP1.3からは「カスタムルーティング」という機能が備わり、その中でチェックしたりデフォルト値を追加したりすることができます。モデルに登録されている値のみをルーティングし、登録されていない値はアクセスできないようなルーティングを表現してみましょう。カスタムルーティングのコードを「app/libs」に記述します。コードを置く場所はどこでもよいのですが、Cake用のコードなのでvendorsではなくlibsがいいでしょう。ここでは「app/libs/viewer_route.php」とします。$result;}}カスタムルーティングでは、parse()とmatch()を記述する事で、それぞれ正引き(Router::connect())と逆引き(Router::url())で独自の処理を行う事ができます。それ以外のコード(上記では__checkViewerId())は独自メソッドです。ClassRegistry::init()を用いると、ルーティング処理内でもモデルを扱うことができます。parse()の段階ではまだコントローラ等は初期化が済んでいませんから、その範囲内での処理しかできないことを留意しておきます。match()は逆引きで用いられるので、タイミング的にcontrollerの初期化が終わっているのでこの限りではありません。次に、「app/config/routes.php」にカスタムルーティングを適用します。第3引数の連想配列の中にある「routeClass」パラメータに作成したカスタムルート名を指定します。このクラスは自動的に読み込まれないので、事前に「App::import()」等で読み込んでおきます。'error'));これで、viewerIdというパラメータで特定ユーザのみを許可するルーティングが実現できます。「ルーティングパラメータに存在しないパラメータを後から追加できる」ことも注目したい点です。上記サンプルでは、モデルから取得したuserIdを追加しています。このパラメータはコントローラ内で「$this->params[‘userId’]」として受け取ることができます。CakePHPは1.2でも十分に実用的ですが、1.3になってよりいろいろなことができるようになりました。今回の「カスタムルーティング」も使い方次第では大変に便利な機能といえます。1.2を含めて、まだまだ便利な機能がCakePHPには備わっています。CakePHP辞典」では、1.2/1.3の違いを含めコアクラス内に収録されているプロパティ・メソッドを盛りだくさんで紹介しています。こちらのほうもぜひご利用いただけますと幸いです。アマゾンのサーバでエラーが起こっているかもしれません。一度ページを再読み込みしてみてください。Libraryのバージョン0.4.0を公開いたします!基本的にはバグフィックスと機種情報などデータ面の更新がメインだったのですが、一つだけ他の携帯向けライブラリ等には存在しない便利な機能を搭載しました。高解像度携帯の登場で、画像の大きさがまちまちになって画面レイアウトが崩れる件については先に搭載しています画像のフィット機能で改善する事ができますが、これだけでは完全に解決することができませんでした。いうと「フォントの大きさ」もキャリア・機種によって異なるため、同じ文字幅で改行する事が困難だったからです。そこで、キャリア・機種によって異なるフォントサイズの指定を肩代わりして同じように見せるような機能を搭載しました。簡単に仕組みを説明しますと、まず3キャリアでフォント使用の指定タグが異なるためそれを吸収し、またキャリア毎、あるいはSoftBankの高解像度携帯とdocomoのブラウザ2.0以降、それ以外での文字サイズの差をなくすために一工夫している感じです。厳密にフォントの大きさを変える事はできません。携帯内が持っているフォントは固定幅でありアウトラインフォントではないため、1ピクセル単位でなめらかに大きさを変える事ができないからです(docomoのブラウザ2.0以降のみできる)。おおむねそれに近い大きさの出力が可能な「small」「medium」「large」の3つの大きさが指定できます。それ以外の大きさも指定は可能ですが、そのまま出力するため同じ大きさに見えるかどうかは分かりません(というか見えないはず)。それから本機能はXHTMLのみ有効です。HTMLでは機能しませんのでお気をつけください。具体的にはこのように使用する事ができます。?></body></html>ktai-devのサンプルにもフォント指定がされていますので、お試しいただく事ができます。FireMobileSimulatorでは正しい文字サイズで表示する事ができませんので注意が必要です。上記サンプルは完全にオプション値を省略していますが、フォント指定を行うタグを変更したり追加のスタイルを与える事もできます。詳しくは添付ドキュメントもしくはソースコード内のコメントを参照してください。ちなみに本機能はフォントの大きさについてあまりこだわりのない方向けの機能ではないのですが、レイアウトにこだわる必要があるサイト、特に携帯ソーシャルサイトなどに便利にご利用いただけると思います(というか当方の案件で必要だったため制作しました(笑))。(木)【CakePHP辞典】Tips第3回:Model::read()ModelのTipsが続いてしまいますが、今回はModel::read()についての注意事項です。通常Modelでデータソースからのデータの読み出しはModel::find()/findBy()を用いるのが一般的だと思いますが、ほかの読み出し方法もいくつか存在しています。その中に今回取り上げます「Model::read()」がありますが、こちらは「プライマリIDを指定してレコード取得」を行うことができます。$fields));」に近いと思いますが、意味的にはfindById($id)のほうが近いかもしれません。取り出し方、結果そのものについてはこれらはそれほど差がありませんが、ひとつだけread()には注意点があります。「Model::validationErrors」プロパティにはモデル保存等でバリデーションエラーが存在する場合にそのエラーメッセージが蓄えられるのですが、read()を実行すると問答無用で初期化します。「Model::validationErrors」プロパティを初期化するメソッドは、「Model::read()」のほか「Model::create()」「Model::saveAll()」の合計3メソッドです。read()はcreate()のように「モデルを初期化するためのメソッド」という位置づけなのでしょう。create()はコードで初期値を与えますが、read()は既存のレコードから初期値を与える、という感じですかね。バリデーションエラーを保持して読み換えるような場合はread()は使うべきではない、ということになります。find()/findById()のほうがよいと思います。個人的にはread()はほとんど使わないため「フーン」な仕様なのですが、bakeコマンドでコードを作り出している場合にはread()が含まれたコードを生成するそうなので、注意が必要です。CakePHP辞典」の55ページに掲載されています。CakePHP辞典」を是非よろしくお願いします!アマゾンのサーバでエラーが起こっているかもしれません。一度ページを再読み込みしてみてください。CakePHP辞典」内で、Modelクラスで主要機能でもある「Model::save()」内の解説について、若干足りない部分がありましたので追加させていただきます。バリデーションを行う場合はtrue。他のオプションを与えたい場合は連想配列で指定。保存するフィールド名の配列。nullの場合は現在の$this->whitelistの保存指定を空にする。コールバックメソッドを実行する場合にtrue。「before」でbeforeSave()を、「after」でafterSave()を実行する$validateは、そのものの値はbooleanですが、連想配列を与えることもでき、一般的な$optionsと同じようにオプション値としてふるまいます。この場合は$fieldListは無視されますので、必要なら$validate内に含めます。「callbacks」というパラメータを与えることもできます。通常trueであり「beforeSave()」「afterSave()」コールバックを通過しますが、falseにすることで通過しません。「before」「after」とすることでbeforeSave()だけ、afterSave()だけ通過させることもできます。このcallbacksオプションは「Model::saveAll()」のオプション値としても有効です。saveAll()は内部でsave()をコールしているためです。CakePHP辞典」の58ページおよび61ページに掲載されています。CakePHP辞典」を是非よろしくお願いします!アマゾンのサーバでエラーが起こっているかもしれません。一度ページを再読み込みしてみてください。