細かすぎて伝わらないCakePHP Pluginシリーズ "Setting plugin" #cakeadvent2012 Day13

CakePHP Advent Calendar 2012 13日目の記事です。

12日は@Ugatsさんの「どこからCakePHPを使えるといっていいのか。」でした。

個人的には、(以前からPHPで開発されていた方限定ですが)「CakePHPを使って便利だなと思えたら使えている」んではないかと思っています。

さて、今年2回目の登場なわけですが、日ごろエントリーを書いていないのでこういうときに書かないとCakePHP界隈から忘れさられてしまいそうなので。

日ごろエントリーを書かなかったからといって、別にプログラムも書いていなかったわけではなく、ガシガシCakePHPで書いています。

最近はzenpreも開発版リリースということでCakePHPでのリニューアルを進めており(以前はRails)、受託案件と並行して楽しい開発ライフを送っています。


CakePHPも既に枯れたフレームワークで、開発効率最高潮か!?」というとそうでもなく、自分はいまだにプラグインやライブラリを作ることがあります。

で、紹介エントリーを書かないでTwitterでつぶやくだけだったりするので、だいたい自分のGitHubリポジトリに埋もれていますが「使っていない」わけではなく、かなり活用をしていたりします。

というわけで、今回は「細かすぎて伝わらないCakePHP Pluginシリーズ」と銘打って、自作の細かいプラグインを紹介したいと思います。

今回はSetting pluginです。

(「シリーズ」とありますが、シリーズ化するかは分かりません)

Setting plugin


Setting: Database driven setting plugin for CakePHP


このプラグイン、細かいです。何が細かいかというと「便利と思われるシチュエーション」が細かいです。

1.設定値の管理どうしている?

皆さんは、普段システム開発をしていて「設定値」をどう管理していますか?

例えば「パスワードの長さ」とか「メールのfrom

などなど。

まあ、開発当初は「ずっと変わらないから」という理由でソースコードに書きますよね?自分は書きます。

2.小さな仕様変更

で、運用を開始して良くあるのが 「やっぱりパスワードの長さは6文字じゃなくて8文字で」とか 「fromのメールアドレス変わりましたー」とか いうような「細かい」仕様変更。

細かいんだけど、プログラムの修正とデプロイが必要になってしまうという。追加工数をもらうようなものではないんだけど、確実に時間がかかる。

で、まあここまではよいと思います。

3.設定変更画面が欲しい

やっぱりいろいろな設定を画面から自由に変更できるほうがいいよね

。。。

。。

いろいろ凹みます。

まさにこのタイミングで「Setting pluginで設定値管理していて良かった!」となるのです!(細かい)

Setting pluginの仕組み

簡単です。要は、設定値関係をデータベースに保存する形で管理しているだけです。

Setting pluginはデフォルトではsettingsテーブルを利用して設定値を管理します。

ポイントは、$this->Setting->find() ではなくて、Configureクラスのように Setting::getSetting([key]) と、どこでも呼べるように作っている点です。

ただ、Configureと異なるのは、「あらかじめ設定できるkeyを限定する(やみくもに設定させない)」という点と「設定するkeyの値にバリデーションチェックを行える」という点です。

具体的には例えば、以下のように設定します。

Configure::write('Setting.settings', array(
    'password_min' => array('rule' => array('numeric'),
                            'default' => 6),
));

上記のように設定するとSetting pluginで設定管理できるのはpassword_minだけです。さらに値入力時(Setting::setSetting())には数値チェックがかかります。

さらに、defaultオプションを書いていれば、最初に自動でデータベースへ設定値を保存してくれます。

上記のように設定するだけで全ての設定が完了し、Setting::getSetting('password_min');と書いて設定値を取得することができます。

データベースの値を直接修正すれば、(キャッシュが消えたタイミングで)設定を永続的に変更できるので、ソースコード変更いらずです。

また、基本的にキャッシュを活用するので、常にデータベースにアクセスするわけではありません。

Setting::setSetting('password_min', $length);といった設定変更機能も実装できます。

Setting pluginで管理していると、いざ設定変更機能を作りやすい

そうなんです。

Setting::setSetting([key], [value]);もあるし、バリデーションも設定可能。」ということは、いざ「設定変更画面」を作るときに非常に楽なんです。

モデル部分は既に作っているようなものです。


まあ、


そこまでになることはなかなかないですかね。。。。

というわけで

「細かすぎて伝わらないCakePHP Pluginシリーズ」 Setting pluginの紹介でした。

"recipe - CakePHP CLI Package Installer -"とは何だったのか #cakeadvent2012 Day5

さてCakePHP Advent Calendar 2012 5日目の記事です。

昨日は@yandoさんのコールバックはもう古い!CakePHPのEventを使おうです。

個人的にまだ謎の多いCakeEventですが、ちょっと使う気になりました。

ちなみに自分は、Nodeを使っているとon()とかemit()とか頭がこんがらがるようなレベルです。

今日はrecipeというCakePHP専用のパッケージインストーラを紹介したいと思います。

まず初めに言っておきたいことがあります。

今回紹介するrecipe.phpは、既に廃れることを約束されたライブラリです。いや、既にオワコンとなってしまいました。

なぜかというとPHPのパッケージ管理システムとして勢いのあるComposerのCakePHP用の導入エントリーが出たからです。

じゃあ、なぜ紹介をするのかというと

かつてrecipeというインストーラがあったということを知ってもらいたかった

ただそれだけです。Composerが使える人はComposerを使うべきです。

recipeとは何だったのか

CakePHPは既にメジャーバージョンは2になり、Plugin(ライブラリ)も非常に充実しています。

フルスタックのPHPフレームワークとはいえ、開発する際には「CakePHPを設置後、定番のPluginを配置していく」というのが常となっているのではないでしょうか。

自分の場合、特に活用するPlugin(ライブラリ)が多く、余裕で2ケタのPluginを配置します。最近話題となったこの記事でも7つのPluginが挙げられていますね。

そうすると毎回配置するのが面倒になってきます。

解法として、Plugin配置済みの環境を使いまわしてもいいですし、gitsubmoduleを活用してもいいかもしれません。

ただ自分は「お手軽に」「gitやsubversionに依存せず」ライブラリの設置をしたかったので

  • PHPファイル1つで
  • 実行したらCakePHPのいつもの対話シェルで

インストールできるものを作ってみた、というのがrecipeです。

recipeの使用方法

本当はいろいろ機能があって、カスタマイズなどもできるのですが、既にオワコンなので通常の使用方法だけ。

  • recipe.phpをダウンロード
  • CakePHPのプロジェクトルートディレクトリでphp recipe.php
  • 後はbakeと同じ対話式

簡単。PHPファイル1つというのも導入が楽でよいですし、CakePHP bakerにとって「bakeの対話シェルと一緒」というのも意外に安心できます。

さらに言うとPluginを1つ1つ設置することも、設定を書いて一括設置することも可能です。

デフォルトで設置できるライブラリは、ingredients.phpに書いているものだけですが、 独自に拡張も可能です。(自分はAuthor権限をフル活用して、普段使うPlugin(ライブラリ)は新しいもの以外は大抵直接書いてコミットしていますが)

こんなに便利なのに…

なのに…

のに…

というわけで

便利なのに、世に出るタイミングを逃したrecipeの紹介でした。自分はもう少しの間使っていこうと思います。

明日は「タコヤキさん」こと@tkykmwさんです。ちなみに「タコヤキさん」と勘違いしていたのは自分だけなので注意してください。

以上です。

CakePHP PluginをTravis CIに載せる

せっかくTravis CIという面白いサービスがあってPHPの環境も用意されているのに、Travis CIに載っているCakePHP Pluginが見つからなかったので載せてみた。

いろんなPluginを作ってた分、いろいろなパターンの.travis.ymlを書くことになったので、他のbakerの参考になるかも。

通常パターン(DBはMySQLだけ)

https://github.com/k1LoW/Yacsv/blob/master/.travis.yml


CakePHPのPluginをテストするのにはいくつか面倒なことがあって、1つはCakePHP自体がないとテストできないこと。

これは『wgetCakePHPを設置するところから書く』という直球な方法で対応可能。


もう1つの面倒なことはCakePHPのデフォルトのディレクトリ構成

CakePHPのPluginは、本来CakePHPのプロジェクト内に設置されるものだけど、今回はPluginのリポジトリのテストなのでトップディレクトリにPluginのフォルダがあることになる。

これは、CakePHPを設置後bootstrap.phpでApp::build()を使ってPluginのパスを再設定するのがポイント。

branchでCakePHPのメジャーバージョンが違う場合

https://github.com/k1LoW/controller_prefix/blob/master/.travis.yml
https://github.com/k1LoW/controller_prefix/blob/2.0/.travis.yml


それぞれのbranchで.travis.ymlを設置すればいい。単純。

ただ、CakePHP2.xのテストスイートはTravis CIがサポートしているPHPUnitを利用しているからいいけれども、
CakePHP1.xはSimpleTestなのでそれも設置の必要がある。wgetwget

複数の種類のDBでテストをしたい場合

https://github.com/k1LoW/glue/blob/master/.travis.yml


envのパターンを作って対応する。
当然接続DBのパターンも動的に変更する必要がある。
database.phpをechoを使って対応しようとしたけど、なぜかうまく通らなかったので別ファイルを設置する形になった。

というわけで

CakePHP Pluginをリポジトリに持っているbakerはみんなTravis CIに載せよう!

「ふつうのform」のためにFuzzy plugin for CakePHPを作ってみた

ふつうのformをつかいたい - はまちや2 - ニコニコ超会議2012を見て「確かになー」と思うところが多々あったので、
「ふつうのform」を作るための簡単なユーティリティをまとめる目的でFuzzy pluginを作ってみた。


k1LoW/Fuzzy · GitHub

Fuzzy pluginって何?

Fuzzy pluginは主に何をするかというと、「ユーザの入力を決められたルールに従って調整するために変換/分割」する(AdjustableBehavior)。

各フィールドに

  • mb_convert_kana()
  • trim()
  • mb_str_replace()
  • 電話番号分割
  • 郵便番号分割
  • 住所分割

などの調整のためのルールを設定することで、CakePHPのバリデーションチェック前にユーザの入力をシステム側の都合に合わせたフォーマットに変換できる。
詳しい使い方はテストケースを参照。

入力の分割ロジック

気になる分割のロジックは、

  • 電話番号:総務省の市外局番リストを利用して作成
  • 郵便番号:3桁と4桁に分けるだけ
  • 住所:郵便局の住所データを利用して独自に正規表現を作成。一応全住所対応(ただし、正しい住所入力に限る)

だったりするので利用は自己責任で。

今後

「システム側の都合」はもう少しいろいろあると思うので、ぼちぼち対応していってみたい。

CakePHP CLI Package Installer 'recipe' を開発中

CakePHP勉強会 2012春 @東京が、定員を増やしては上限オーバー、定員を増やしては上限オーバーと何回も繰り返した結果、大変な人数になってきている。


はじめは40人程度じゃなかったっけ?


当日たまたま東京にいるので、気軽に参加表明したら「プラグインバトルロワイヤル」というガチンコなCakePHP Plugin発表セッションに参戦することに。


おそらく「おれのかんがえたさいきょうのぷらぐいん」の発表大会みたいなことなりそうなので、ある意味メタ的に、その「さいきょうのぷらぐいん」をインストール(設置)できるパッケージインストーラを作ってみた(開発中)。


recipe - CakePHP CLI Package Installer -


もともとRailsのBunderのもっと簡易的なものが欲しかったのと、社内で使っていた独自インストーラが1.3までしか対応していなかったので、改めて設計をし直している。まだ仕様は確定していない。と思う。

今のところの特徴としては

  1. 実行は1つphpファイルをダウンロードして実行するだけ(Pluginですらない)。そのくせ、CakePHPのShellクラスを利用するので見た目がbakerにも優しい。
  2. デフォルトのパッケージリストの他に、独自にパッケージリストを指定可能
  3. パッケージの一括インストールリストの指定も可能
  4. CakePHPのPluginに限らず、PHPライブラリを任意のディレクトリに設置可能
  5. GNUコマンドを使いまくっているのでLinuxのみ対応( Windows?なにそれ? )


2と3を指定するための設定ファイルを便宜上「レシピ」と呼んでいるのだけれども、
2と3のおかげで、「社内のクローズドな環境にあるPluginやライブラリを設置できたり」「いつも使うライブラリを一括インストールできる」レシピを作成できる。
また、レシピはリモートファイルを指定できるので、

php recipe.php -r https://raw.github.com/gist/1929041/536e6ac9735956d2f69af15e585be3a5907b22d0/myrecipe.php

なんてことも可能。そのうちCakePHPで作ったCMSみたいなシステムのアップデータみたいなものにも使えるようになるかもしれない。


まだ、実現したい機能を全て実装できていないので、まずは日々の業務に耐えられるように拡張していきたい。


何か良いアイデアがあれば教えてください。

CakePHPでの管理者機能の分け方いろいろ[CakePHP Advent Calendar 2011 Day6]

CakePHP Advent Calendar 2011の6日目です。
前回は@kachiokaさんでした。
CakePHPにおける複数形はCakePHP自体がどう判定するのかがInflectorクラス次第ですからね。
ちなみにcake.elはInflectorクラスをEmacs Lispインプリメントして利用しているので安心です。


さて、本題です。
システムを作っていると、一般ユーザ側と管理者側の機能に分かれることが多いですよね。
で、一般ユーザの機能と管理者側機能は「似ているけど異なる」という微妙な感じになるのもよくあることです。

ただ、微妙とはいえ一般ユーザと管理者とではできることが違うので、それぞれの機能を何かしらの形で明確に分ける必要があります。
周りをみているといろいろ方法があるのでちょっとまとめてみました。

分離したいものは「URL」だったり「機能」だったり「親クラス」だったりしますが、そこはあえて限定しないで考えてみます。

ちなみに諸事情によりCakePHP1.3系を対象とします。

1.action内で条件分岐で分ける

例えばモデルのUser.admin_flgなどを見て機能を分ける方法があります。
これは「機能」のみを分けることになります。
簡単ですが、機能の乖離がでてくると条件分岐がでてきて面倒だったりします。
個人的にはあまりお勧めしません。

2.Routing.prefixesを利用してactionごとに分ける

app/config/core.php

<?php
Routing.prefixes = array('admin');

と書けば、PostsController::admin_add()がadmin/posts/addにルーティングされるというCakePHPの機能ですね。
これは「URL」「機能」を分けることになります。
ソースのコメントに"admin"とあることから、ある程度管理機能などに使うことを想定しているのでしょうか。

3.AdminAppControllerクラスをつくって継承することで分ける

AdminAppControllerクラスをapp/app_controller.phpに記述したり、libsに入れてそれを呼びだして継承したりする手法ですね。
AppControllerを継承しているのか、AdminAppControllerを継承しているのかで渡すパラメータや共通処理などを変えたりします。
これは「機能」「親クラス」を分けることになります。

4.Controller prefix pluginを利用してコントローラごとに分ける

拙作のController prefix pluginを利用することで、
従来のaction名ではなくコントローラ名でルーティングができるようになります。
例えば、route.php

<?php
App::import('Lib', 'ControllerPrefix.ControllerPrefixRoute');
Router::connect('/admin/:controller/:action/*',
                array('controllerPrefix' => 'admin'), array('routeClass' => 'ControllerPrefixRoute'))

と設定することで、admin_posts_controller.phpのAdminPostsController::add()がadmin/posts/addにルーティングされます。
これは「URL」「機能」を分けることになります。3と併用すれば「親クラス」も分けることができますね。


5.プロジェクトフォルダ(appフォルダ)ごとに分ける

大規模なプロジェクトになると結構これが良かったりします。
App::build()を利用してComponentやPluginなどをまとめてしまう方法ですね。
これは「URL」「機能」を分けることになります。

まとめ

一般ユーザ側と管理者側の機能の分離方法について考えてみました。
どれが最適なのかは「そのシステムによりけり」なのでしょうけど、
いろいろ方法のアイデアを知っておくと後々便利だと思います。
他にもいろいろ方法があると思うので是非教えてください。


さて、明日は@msngさんです。お楽しみに。

いつまでたってもゴールが見えないのでCalendar Plugin for CakePHPをアルファリリースした

いつまでたってもゴールが見えないのでCalendar Plugin for CakePHPをアルファリリースした。

https://github.com/k1LoW/calendar

Calendar Pluginって何?

CakePHPでカレンダー機能を実装する時に便利になったらいいなと思って『作り始めた』プラグイン。
大きな特徴としてiCalendar形式を意識したつくりになっていること。

iCalendar形式についてはRFC2445を参照。英語と複雑な仕様で頭が痛くなるので必見。
MacのiCalやGoogle Calendarが採用している形式といったらわかりやすいかも。

Calendar Pluginはイベント(1つ1つ予定のこと。VEVENT)をDBに保存するのだけれども、そのスキーマが完全にiCalendar形式を意識している。
どんなPluginかわからないと思ったので、CakeDCにならってサンプルアプリケーションも作ってみたので詳しくはそちらで「感じて」下さい。
今のところVEVENTしか実装しはじめていないし、VEVENTしか実装しないつもり。

https://github.com/k1LoW/Sample-Calendar-Application

なんでアルファリリース?

まだ、納得できるところまで実装できていないから。
というか、iCalendarの仕様が複雑すぎてどこがゴールか分からないし、どこまで正しいか分からないから。
せめてGoogle Calendarができているところまでは実装したい。
あとEXDATE属性が実装できればOKなはず。

どうやってテストしているの?

基本的な機能はRFCを読みつつテストケースを作成して実装。
ただ、属性の条件が複雑すぎて読み取れないので、
あとはひたすらRFCに載っているサンプルをテストケースに落とし込んで一つ一つクリアしていっている。
さらに気になるところは自分でテストケースを追加して実装していっている。

注目すべきはCalendar PluginはRFC2445を読みきっていない人間が作っている点。
RFCから作ったテストケース以外は、「テストケース自体が間違っている」ことがありそうで怖い。

その他やりたいこと

iCalendar形式のファイルのインポート/エクスポート機能

iCalendar形式のサブセットになっているということは、
iCalendar形式のファイルのインポートやエクスポートの実装が容易ということになる。
これはVEVENTの実装が落ち着いたら実装する予定

祝日などの日付に対するフィルタ機構

表示時に土日や祝日の属性を自由に与えられるようなフィルタ機構を実装したい

エクストラな属性を付与できるフック機構

iCalendar形式はおそらく「個人のスケジュール」を意識した作りになっているので、
「みんなのスケジュール」や「複数のスケジュール」を管理するためにはもう一工夫が必要。
そういうイベントに付与されるエクストラな仕様に柔軟に対応できる機構を作りたい。
Filebinderで実装したような仮想フィールドみたいなことができればいいかな。

最後に

このPluginはPHPMatsuri2011で生まれました。
(vevent_fixture.phpにPHPMatsuri2011のイベントが登録されているのはそのせい)
また、ハック大賞次点をいただくことができました!感謝!
あのPHPMatsuriのストイックなハック環境は楽しくて最高ですね!

このPluginがこのまま終わらず、
実用的なものになるように地道に開発を続けていきたいと思います!