<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>へびにっき &#187; CakePHP</title>
	<atom:link href="http://wp.serpere.info/archives/category/programing/cakephp-programing/feed" rel="self" type="application/rss+xml" />
	<link>http://wp.serpere.info</link>
	<description>樹上で暮らすヘビのように生きたい</description>
	<lastBuildDate>Thu, 09 Feb 2012 11:35:51 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>CakePHPで特定のコントローラに対するBasic認証をApache側でかけようとしたが無理だった</title>
		<link>http://wp.serpere.info/archives/1883</link>
		<comments>http://wp.serpere.info/archives/1883#comments</comments>
		<pubDate>Tue, 16 Nov 2010 11:48:08 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1883</guid>
		<description><![CDATA[2010-11-17: 記事のタイトル・内容を修正しました。最終的に、Cakeの特定のコントローラにApache側で認証をかけることは不可能という結論に至りましたので、「なぜ不可能なのか」を説明する内容に差し替えました。コメント欄にて重要な指摘をくださったshin1x1さんに感謝します。 CakePHP 1.2/1.3 CakePHPで特定のコントローラ（URL）に対して、Apacheの機能を使ってBasic認証をかけようとして、実際にその方法を見つけたとして記事を公開したのですが、無理だということに気がつきました。 Cakeは最終的に $_GET['url'] しか見ていないので、一つでも認証無しでアクセス可能なコントローラ/アクションが存在すれば、 /controller/action?url=/protected というパラメータを使うことで任意のURL（上では /protected）に対して認証無しでアクセスできてしまいます。 以下に私が使おうとしていた .htaccess のコードを示しておきます。これは同じようなアイデアを思いついた人に対して、このような方法では無理だということを示すためのものなので、決して使用しないでください。 # Basic認証の設定 AuthType Basic AuthName "Members only" AuthUserFile /path/to/.htpasswd Require valid-user # 認証対象となるURLの指定 SetEnvIf Request_URI ".*" allowed SetEnvIf Request_URI "^/members" !allowed # !INSERTED! /index.php に直接アクセスするのを許可しない SetEnvIf Request_URI "^/index\.php" !allowed # 認証をバイパスさせるための設定 Order Deny,Allow Deny from all Allow from env=allowed Satisfy Any [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1883%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22CakePHP%E3%81%A7%E7%89%B9%E5%AE%9A%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8BBasic%E8%AA%8D%E8%A8%BC%E3%82%92Apache%E5%81%B4%E3%81%A7%E3%81%8B%E3%81%91%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%81%8C%E7%84%A1%E7%90%86%E3%81%A0%E3%81%A3%E3%81%9F%22%20%7D);"></div>
<p>
<strong>2010-11-17:</strong> 記事のタイトル・内容を修正しました。最終的に、Cakeの特定のコントローラにApache側で認証をかけることは<strong style="color:red">不可能</strong>という結論に至りましたので、「なぜ不可能なのか」を説明する内容に差し替えました。コメント欄にて重要な指摘をくださったshin1x1さんに感謝します。
</p>
<p>
CakePHP 1.2/1.3
</p>
<p>
CakePHPで特定のコントローラ（URL）に対して、Apacheの機能を使ってBasic認証をかけようとして、実際にその方法を見つけたとして記事を公開したのですが、無理だということに気がつきました。
</p>
<p>
Cakeは最終的に <code>$_GET['url']</code> しか見ていないので、一つでも認証無しでアクセス可能なコントローラ/アクションが存在すれば、
</p>
<pre>
/controller/action?url=/protected
</pre>
<p>
というパラメータを使うことで任意のURL（上では /protected）に対して認証無しでアクセスできてしまいます。
</p>
<p>
以下に私が使おうとしていた .htaccess のコードを示しておきます。これは同じようなアイデアを思いついた人に対して、<strong>このような方法では無理だ</strong>ということを示すためのものなので、決して使用しないでください。
</p>
<pre>
# Basic認証の設定
AuthType Basic
AuthName "Members only"
AuthUserFile /path/to/.htpasswd
Require valid-user
 
# 認証対象となるURLの指定
SetEnvIf Request_URI ".*" allowed
SetEnvIf Request_URI "^/members" !allowed
# !INSERTED! /index.php に直接アクセスするのを許可しない
SetEnvIf Request_URI "^/index\.php" !allowed
 
# 認証をバイパスさせるための設定
Order Deny,Allow
Deny from all
Allow from env=allowed
Satisfy Any
 
# 通常のCakeのrewrite設定
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</pre>
<p>
なおこの記事は以下のブログ記事を参考にして書きましたが、同様の問題が存在すると考えられますので注意してください。
</p>
<ul>
<li><a href="http://d.hatena.ne.jp/cakephper/20100224/1266998300">Cakephpで任意のコントローラにBASIC認証をApache側でかける &#8211; cakephperの日記</a></li>
<li><a href="http://d.hatena.ne.jp/u1tnk/20100610/1276231952">apacheでmod_rewrite+Basic認証時に特定パスのみ認証を解除する &#8211; u1tnk日記</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1883/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>テスト時に全テーブルのfixtureを自動で読み込む</title>
		<link>http://wp.serpere.info/archives/1786</link>
		<comments>http://wp.serpere.info/archives/1786#comments</comments>
		<pubDate>Thu, 21 Oct 2010 11:36:46 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1786</guid>
		<description><![CDATA[環境:CakePHP 1.3 テスト時に誰もが一度は経験するであろう Missing Database Table Error: Database table users for model User was not found. というエラーを回避する方法です。 …… CakePHPのテストでは必要なfixtureを全て手動で列挙する必要があります。一つ二つなら良いのですが、モデルにアソシエーションを設定すると関連するテーブル全てが再帰的に必要になるので、非常に面倒です。 それならいっそ全テーブルを自動で読み込んでくれよ、ということで自動で読み込む方法を考えました。以下のクラスに示す2メソッドを CakeTestCase のサブクラスで定義してください（CakeTestCaseを独自の拡張クラスに置き換えるも参照）。 例えばdefaultデータベースに users, posts, tags, posts_tags の4つのテーブルがある場合、 $fixtures = array&#40;'IMPORT' =&#62; 'default'&#41;; と書くと $fixtures = array&#40;'app.user', 'app.post', 'app.tag', 'app.posts_tag'&#41;; と書いたのと同じことになります。 やっていることは非常に単純で、指定されたデータソースからテーブル一覧を得て app.fixture_name の形式で $fixtures に追加しているだけです。 もし特定のfixtureがコンフリクトする場合は除外するfixtureを EXCLUDE キーで指定してください。 //usersテーブルは special_user フィクスチャからインポートするので //app.user は読み込まない $fixtures [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1786%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22%E3%83%86%E3%82%B9%E3%83%88%E6%99%82%E3%81%AB%E5%85%A8%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AEfixture%E3%82%92%E8%87%AA%E5%8B%95%E3%81%A7%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80%22%20%7D);"></div>
<p>
環境:CakePHP 1.3
</p>
<p>
テスト時に誰もが一度は経験するであろう
</p>
<pre>
<strong>Missing Database Table</strong>
Error:  Database table <em>users</em> for model <em>User</em> was not found.
</pre>
<p>
というエラーを回避する方法です。
</p>
<p>……</p>
<p>
CakePHPのテストでは必要なfixtureを全て手動で列挙する必要があります。一つ二つなら良いのですが、モデルにアソシエーションを設定すると関連するテーブル全てが再帰的に必要になるので、非常に面倒です。
</p>
<p>
それならいっそ全テーブルを自動で読み込んでくれよ、ということで自動で読み込む方法を考えました。以下のクラスに示す2メソッドを CakeTestCase のサブクラスで定義してください（<a href="http://wp.serpere.info/archives/1750">CakeTestCaseを独自の拡張クラスに置き換える</a>も参照）。
</p>
<script src="http://gist.github.com/638322.js?file=fixture_loader_test_case.php"></script>
<p>
例えばdefaultデータベースに users, posts, tags, posts_tags の4つのテーブルがある場合、
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$fixtures</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IMPORT'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'default'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<p>
と書くと
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$fixtures</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'app.user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'app.post'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'app.tag'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'app.posts_tag'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<p>
と書いたのと同じことになります。
</p>
<p>
やっていることは非常に単純で、指定されたデータソースからテーブル一覧を得て <code>app.fixture_name</code> の形式で <code>$fixtures</code> に追加しているだけです。
</p>
<p>
もし特定のfixtureがコンフリクトする場合は除外するfixtureを EXCLUDE キーで指定してください。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//usersテーブルは special_user フィクスチャからインポートするので</span>
<span style="color: #666666; font-style: italic;">//app.user は読み込まない</span>
<span style="color: #000088;">$fixtures</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'app.special_user'</span><span style="color: #339933;">,</span>
                  <span style="color: #0000ff;">'IMPORT'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'default'</span><span style="color: #339933;">,</span>
                  <span style="color: #0000ff;">'EXCLUDE'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'app.user'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<p>
おまけ：
</p>
<p>
以下の2メソッドも加えると存在しないfixtureクラスを自動生成してくれます。
</p>
<script src="http://gist.github.com/638322.js?file=fixture_loader_test_case2.php"></script>

]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1786/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakeTestCaseを独自の拡張クラスに置き換える</title>
		<link>http://wp.serpere.info/archives/1750</link>
		<comments>http://wp.serpere.info/archives/1750#comments</comments>
		<pubDate>Mon, 06 Sep 2010 07:43:34 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1750</guid>
		<description><![CDATA[環境: CakePHP 1.3 CakePHPでTestCaseの機能を拡張したい場合、CakeTestCase クラスを継承した独自のベースクラスを作る。 abstract class MyTestCase extends CakeTestCase &#123; function assertHoge&#40;&#41; &#123; //... &#125; &#125; しかし標準ではこのクラスを自動的に読み込む手段がない。各テストファイルの先頭で毎回 App::import するのはあまりにも面倒なので、自動で読み込むための方法を調べてみた。 前提： 必要なファイルは全て一つのプラグイン（以下 my_test）の中にまとめる Webからの実行（test.php）、コンソールからの実行（cakeshell）、両方に対応する my_test/config/bootstrap.php この bootstrap.php の中で MyTestCase はじめとする必要なクラスファイルを読み込む。下の例では ComponentTestCase も読み込んでいる。 my_test/libs/test_suite_dispatcher.php test.phpからの実行時に必要なファイル my_test/vendors/shells/my_test.php コンソールからの実行に必要なファイル 以上の3ファイルが app/plugins/my_test 以下にあれば良い。 コンソールから実行する場合 cake testsuite の代わりに cake my_test を実行するだけ。 Webからtest.phpで実行する場合 test.php の書き換えが必要。といってもファイル末尾の CakeTestSuiteDispatcher を MyTestSuiteDispatcher に入れ替えるだけ。 require_once CAKE_TESTS_LIB [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1750%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2Fbumx8i%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22CakeTestCase%E3%82%92%E7%8B%AC%E8%87%AA%E3%81%AE%E6%8B%A1%E5%BC%B5%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AB%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88%E3%82%8B%22%20%7D);"></div>
<p>
環境: CakePHP 1.3
</p>
<p>
CakePHPでTestCaseの機能を拡張したい場合、CakeTestCase クラスを継承した独自のベースクラスを作る。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">abstract <span style="color: #000000; font-weight: bold;">class</span> MyTestCase <span style="color: #000000; font-weight: bold;">extends</span> CakeTestCase <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">function</span> assertHoge<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">//...</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>



<p>
しかし標準ではこのクラスを自動的に読み込む手段がない。各テストファイルの先頭で毎回 App::import するのはあまりにも面倒なので、自動で読み込むための方法を調べてみた。
</p>
<p>
前提：
</p>
<ul>
<li>必要なファイルは全て一つのプラグイン（以下 my_test）の中にまとめる</li>
<li>Webからの実行（test.php）、コンソールからの実行（cakeshell）、両方に対応する</li>
</ul>
<h3>my_test/config/bootstrap.php</h3>
<p>
この bootstrap.php の中で MyTestCase はじめとする必要なクラスファイルを読み込む。下の例では <a href="http://wp.serpere.info/archives/1230">ComponentTestCase</a> も読み込んでいる。
</p>
<script src="http://gist.github.com/566741.js?file=bootstrap.php"></script>

<h3>my_test/libs/test_suite_dispatcher.php</h3>
<p>test.phpからの実行時に必要なファイル</p>
<script src="http://gist.github.com/566741.js?file=my_test_suite_dispatcher.php"></script>

<h3>my_test/vendors/shells/my_test.php</h3>
<p>コンソールからの実行に必要なファイル</p>
<script src="http://gist.github.com/566741.js?file=my_test.php"></script>

<p>
以上の3ファイルが app/plugins/my_test 以下にあれば良い。
</p>
<h3>コンソールから実行する場合</h3>
<p>
cake testsuite の代わりに cake my_test を実行するだけ。
</p>
<h3>Webからtest.phpで実行する場合</h3>
<p>
test.php の書き換えが必要。といってもファイル末尾の CakeTestSuiteDispatcher を MyTestSuiteDispatcher に入れ替えるだけ。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require_once</span> CAKE_TESTS_LIB <span style="color: #339933;">.</span> <span style="color: #0000ff;">'cake_test_suite_dispatcher.php'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//</span>
App<span style="color: #339933;">::</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'lib'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'MyTest.MyTestSuiteDispatcher'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$Dispatcher</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MyTestSuiteDispatcher<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//</span>
<span style="color: #000088;">$Dispatcher</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">dispatch</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<p>
参考: <a href="http://d.hatena.ne.jp/zainin/20100615/1276685886">CakePHP1.3 CakeTestCase の拡張を読み込む bootstrap 的なものをつくる</a>
</p>

]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1750/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CakePHPのデータベース情報を使ってmysqlコマンドで接続する</title>
		<link>http://wp.serpere.info/archives/1745</link>
		<comments>http://wp.serpere.info/archives/1745#comments</comments>
		<pubDate>Fri, 03 Sep 2010 08:36:50 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1745</guid>
		<description><![CDATA[環境: CakePHP 1.3 CakePHPでの開発中、コマンドラインから直接SQLを実行したいことがままあるので、CakePHPのdatabase.phpから情報を取得してmysqlコマンドで接続するためのシェルスクリプトを作った（要CLI版php）。 connect_db.sh 何もオプションを指定しなければそのままmysqlのインタラクティブシェルに入る。 ./connect_db.sh コマンドライン引数はそのままmysqlコマンドに渡されるので、例えば -e オプションを使うとそのままSQLを実行できる。 ./connect_db.sh -e 'select * from users' 標準では default 接続が使われる。その他の接続設定を使いたい場合は connect_db.sh に対して connect_db_{接続名} という名前でシンボリックリンクを作る。 # DATABASE_CONFIG-&#62;test に接続 ln -s connect_db.sh connect_db_test ./connect_db_test 私の場合 app と同じ階層に bin というディレクトリを作ってそこにシェルスクリプトを置いているので、パスもそれに合わせてある。異なるディレクトリ構成で使う場合は最初のAPPの定義を適宜書き換える。]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1745%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2F9wndsM%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22CakePHP%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E6%83%85%E5%A0%B1%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6mysql%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A7%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B%22%20%7D);"></div>
<p>
環境: CakePHP 1.3
</p>
<p>
CakePHPでの開発中、コマンドラインから直接SQLを実行したいことがままあるので、CakePHPのdatabase.phpから情報を取得してmysqlコマンドで接続するためのシェルスクリプトを作った（要CLI版php）。
</p>
<p><a href="http://gist.github.com/563613">connect_db.sh</a></p>
<p>
何もオプションを指定しなければそのままmysqlのインタラクティブシェルに入る。
</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">.<span style="color: #000000; font-weight: bold;">/</span>connect_db.sh</pre></div></div>



<p>
コマンドライン引数はそのままmysqlコマンドに渡されるので、例えば -e オプションを使うとそのままSQLを実行できる。
</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">.<span style="color: #000000; font-weight: bold;">/</span>connect_db.sh <span style="color: #660033;">-e</span> <span style="color: #ff0000;">'select * from users'</span></pre></div></div>



<p>
標準では default 接続が使われる。その他の接続設定を使いたい場合は connect_db.sh に対して connect_db_{接続名} という名前でシンボリックリンクを作る。
</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># DATABASE_CONFIG-&gt;test に接続</span>
<span style="color: #c20cb9; font-weight: bold;">ln</span> <span style="color: #660033;">-s</span> connect_db.sh connect_db_test
.<span style="color: #000000; font-weight: bold;">/</span>connect_db_test</pre></div></div>



<p>
私の場合 app と同じ階層に bin というディレクトリを作ってそこにシェルスクリプトを置いているので、パスもそれに合わせてある。異なるディレクトリ構成で使う場合は最初のAPPの定義を適宜書き換える。
</p>
]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1745/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPでトランザクション制御</title>
		<link>http://wp.serpere.info/archives/1738</link>
		<comments>http://wp.serpere.info/archives/1738#comments</comments>
		<pubDate>Mon, 30 Aug 2010 08:49:19 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1738</guid>
		<description><![CDATA[環境: CakePHP 1.3 CakePHPのModelクラスには直接トランザクションを制御するメソッドがない。そこで例えば次のようにAppModelにメソッドを定義する。 class AppModel extends Model &#123; function begin&#40;&#41; &#123; return $this-&#62;getDataSource&#40;&#41;-&#62;begin&#40;$this&#41;; &#125; function commit&#40;&#41; &#123; return $this-&#62;getDataSource&#40;&#41;-&#62;commit&#40;$this&#41;; &#125; function rollback&#40;&#41; &#123; return $this-&#62;getDataSource&#40;&#41;-&#62;rollback&#40;$this&#41;; &#125; &#125; しかしこの方法ではテストがやりにくい。明示的にトランザクションを制御したい時というのは、複数のテーブルにまたがる複雑なロジックを組むことが多いので、commit/rollbackされたことを確認するのにいちいちDBの状態を確認していては手間がかかりすぎる。 そもそも「commitされたらそれまでの実行結果が反映される」「rollbackされたらトランザクション開始前の状態に戻る」というのはDBの機能なので、改めてテストし直す意味はない。アプリケーションのテストとしてはcommit/rollbackが発行されたことさえ分かればいい。 そこでAppModelで定義する代わりに、専用のモデルクラスを作ってそこでメソッドの定義を行うことにした。$useTable を false にしてもDataSource自体は取得できるというのがポイントである。 class TransactionManager extends AppModel &#123; var $useTable = false; &#160; function begin&#40;&#41; &#123; return $this-&#62;getDataSource&#40;&#41;-&#62;begin&#40;$this&#41;; &#125; function commit&#40;&#41; &#123; return $this-&#62;getDataSource&#40;&#41;-&#62;commit&#40;$this&#41;; [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1738%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22CakePHP%E3%81%A7%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E5%88%B6%E5%BE%A1%22%20%7D);"></div>
<p>環境: CakePHP 1.3</p>
<p>
CakePHPのModelクラスには直接トランザクションを制御するメソッドがない。そこで例えば次のようにAppModelにメソッドを定義する。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> AppModel <span style="color: #000000; font-weight: bold;">extends</span> Model <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">function</span> begin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getDataSource</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">begin</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">function</span> commit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getDataSource</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">commit</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">function</span> rollback<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getDataSource</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">rollback</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>



<p>
しかしこの方法ではテストがやりにくい。明示的にトランザクションを制御したい時というのは、複数のテーブルにまたがる複雑なロジックを組むことが多いので、commit/rollbackされたことを確認するのにいちいちDBの状態を確認していては手間がかかりすぎる。
</p>
<p>
そもそも「commitされたらそれまでの実行結果が反映される」「rollbackされたらトランザクション開始前の状態に戻る」というのはDBの機能なので、改めてテストし直す意味はない。アプリケーションのテストとしてはcommit/rollbackが発行されたことさえ分かればいい。
</p>
<p>
そこでAppModelで定義する代わりに、専用のモデルクラスを作ってそこでメソッドの定義を行うことにした。<code>$useTable</code> を false にしてもDataSource自体は取得できるというのがポイントである。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> TransactionManager <span style="color: #000000; font-weight: bold;">extends</span> AppModel <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$useTable</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">function</span> begin<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getDataSource</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">begin</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">function</span> commit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getDataSource</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">commit</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">function</span> rollback<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getDataSource</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">rollback</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>



<p>
これでMockを使ったテストができるようになった。トランザクションを使用する際は ClassRegistry 経由でこのモデルを取得する。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$tx</span> <span style="color: #339933;">=</span> ClassRegistry<span style="color: #339933;">::</span><span style="color: #004000;">init</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'TransactionManager'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">begin</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #666666; font-style: italic;">//...</span>
&nbsp;
  <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>doSomething<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">commit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$values</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000088;">$tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">rollback</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span></pre></div></div>



<p>
テスト時には ClassRegistry にMockのインスタンスを登録しておいて、begin/commit/rollbackの各メソッドが呼び出されたことだけを調べる。もちろんそれぞれの操作が失敗した場合のテストもできる。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> startTest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tx</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MockTransactionManager<span style="color: #339933;">;</span>
  ClassRegistry<span style="color: #339933;">::</span><span style="color: #004000;">addObject</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'TransactionManager'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tx</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> testA<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">expectOnce</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'begin'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setReturnValue</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'begin'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">expectOnce</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'commit'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setReturnValue</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'commit'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">tx</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">expectNever</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'rollback'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">//...</span>
<span style="color: #009900;">&#125;</span></pre></div></div>



]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1738/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>フィールドの値をシリアライズするSerializableビヘイビア</title>
		<link>http://wp.serpere.info/archives/1727</link>
		<comments>http://wp.serpere.info/archives/1727#comments</comments>
		<pubDate>Fri, 20 Aug 2010 09:03:18 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1727</guid>
		<description><![CDATA[環境: CakePHP 1.3 特定のフィールドの値をシリアライズしてから保存する Serializable ビヘイビアを作りました。配列などの構造を持つデータを、ひとつのフィールドに保存することができます。 serializable.php &#8211; gist （いずれ正式なリポジトリに移すかもしれない） fields オプションに指定したフィールドがsave時にJSONでエンコードして保存され、find時には自動的にデコードされます（PHP標準の serialize ではなくJSONを使用するのは互換性を重視しているため）。 var $actsAs = array&#40;'Serializable' =&#62; array&#40;'fields' =&#62; array&#40;'field1', 'field2'&#41;&#41;&#41;; &#160; // 保存する前に自動的にJSONエンコードされる $Model-&#62;save&#40;array&#40; 'field1' =&#62; array&#40;1,2,3&#41;, 'field2' =&#62; array&#40;'assoc' =&#62; 'data'&#41; &#41;&#41;; &#160; // find時に自動でデコードされる $values = $Model-&#62;find&#40;'first'&#41;; // field1 == array(1,2,3) // field2 == array('assoc' =&#62; 'data') この種のフィールド・シリアライズには様々なバリエーションが考えられます： JSON以外の形式でエンコードする 複数のフィールドの値をひとつにまとめて保存する [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1727%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FbZKiOc%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AE%E5%80%A4%E3%82%92%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8BSerializable%E3%83%93%E3%83%98%E3%82%A4%E3%83%93%E3%82%A2%22%20%7D);"></div>
<p>環境: CakePHP 1.3</p>
<p>
特定のフィールドの値をシリアライズしてから保存する Serializable ビヘイビアを作りました。配列などの構造を持つデータを、ひとつのフィールドに保存することができます。
</p>
<p>
<a href="http://gist.github.com/539919">serializable.php</a> &#8211; gist<br />
（いずれ正式なリポジトリに移すかもしれない）
</p>
<p>
fields オプションに指定したフィールドがsave時にJSONでエンコードして保存され、find時には自動的にデコードされます（PHP標準の serialize ではなくJSONを使用するのは互換性を重視しているため）。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$actsAs</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Serializable'</span>
  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'fields'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'field1'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'field2'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// 保存する前に自動的にJSONエンコードされる</span>
<span style="color: #000088;">$Model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'field1'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'field2'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'assoc'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'data'</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// find時に自動でデコードされる</span>
<span style="color: #000088;">$values</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'first'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// field1 == array(1,2,3)</span>
<span style="color: #666666; font-style: italic;">// field2 == array('assoc' =&gt; 'data')</span></pre></div></div>



<p>
この種のフィールド・シリアライズには様々なバリエーションが考えられます：
</p>
<ul>
<li>JSON以外の形式でエンコードする</li>
<li>複数のフィールドの値をひとつにまとめて保存する</li>
<li>シリアライズしたフィールドを別のモデルにマップして、hasOne関連のように扱えるようにする</li>
</ul>
<p>
このbehaviorは最も単純な作りになっているので、適当なメソッドを上書きすれば上のような動作も実現できるのではないかと思います。
</p>

]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1727/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>動的にコールバックを設定するObservableビヘイビア</title>
		<link>http://wp.serpere.info/archives/1722</link>
		<comments>http://wp.serpere.info/archives/1722#comments</comments>
		<pubDate>Thu, 19 Aug 2010 13:31:10 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1722</guid>
		<description><![CDATA[環境: CakePHP 1.3 モデル用のコールバック関数を動的に登録/解除できるようにする Observable Behaviorを作りました。コールバックを使用するためだけにサブクラスを作ったりビヘイビアを作ったりする必要がなくなります。 observable.php &#8211; gist （いずれ正式なリポジトリに移すかもしれない） callable なオブジェクトなら何でもコールバックとして使用できますが、PHP 5.3のクロージャと組み合わせると特に便利です。 $actsAs = array&#40;'Observable'&#41;; &#160; // addObserver メソッドで登録。戻り値は一意なid $oid = $Model-&#62;addObserver&#40;'beforeSave', function&#40;$model&#41; &#123; &#160; // 第1引数はモデル、それ以後は通常のコールバック引数 $model-&#62;data&#91;$model-&#62;alias&#93; = ....; &#160; // false を返すとコールバックの実行が停止する // 何も返さなかった場合（null）は true を返したのと同じことになる //return false; &#125;&#41;; &#160; // 不要になったら取り除く $Model-&#62;removeObserver&#40;$oid&#41;; コメント中にもある通り、明示的に引数を返さなかった場合は true と見なされるので、 beforeSave や beforeValidate で戻り値を忘れてその後の処理が実行されない……といったことはありません。]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1722%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2Fbloyjb%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22%E5%8B%95%E7%9A%84%E3%81%AB%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8BObservable%E3%83%93%E3%83%98%E3%82%A4%E3%83%93%E3%82%A2%22%20%7D);"></div>
<p>環境: CakePHP 1.3</p>
<p>
モデル用のコールバック関数を動的に登録/解除できるようにする Observable Behaviorを作りました。コールバックを使用するためだけにサブクラスを作ったりビヘイビアを作ったりする必要がなくなります。
</p>
<p>
<a href="http://gist.github.com/537867">observable.php</a> &#8211; gist<br />
（いずれ正式なリポジトリに移すかもしれない）
</p>
<p>
callable なオブジェクトなら何でもコールバックとして使用できますが、PHP 5.3のクロージャと組み合わせると特に便利です。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$actsAs</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Observable'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// addObserver メソッドで登録。戻り値は一意なid</span>
<span style="color: #000088;">$oid</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addObserver</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'beforeSave'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$model</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// 第1引数はモデル、それ以後は通常のコールバック引数</span>
    <span style="color: #000088;">$model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">data</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alias</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #339933;">....;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// false を返すとコールバックの実行が停止する</span>
    <span style="color: #666666; font-style: italic;">// 何も返さなかった場合（null）は true を返したのと同じことになる</span>
    <span style="color: #666666; font-style: italic;">//return false;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// 不要になったら取り除く</span>
<span style="color: #000088;">$Model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">removeObserver</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$oid</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<p>
コメント中にもある通り、明示的に引数を返さなかった場合は true と見なされるので、 beforeSave や beforeValidate で戻り値を忘れてその後の処理が実行されない……といったことはありません。
</p>
]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1722/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Searchプラグインによる検索条件をページングで引き継ぐ（Prgコンポーネントを置き換える）</title>
		<link>http://wp.serpere.info/archives/1378</link>
		<comments>http://wp.serpere.info/archives/1378#comments</comments>
		<pubDate>Wed, 28 Jul 2010 07:20:37 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1378</guid>
		<description><![CDATA[環境: CakePHP 1.3 CakeDCのSearchプラグインは、全体としては非常に優れたプラグインなのですが、Prgコンポーネントの機能がどうしても私の使い方には合いませんでした。具体的に言うと 検索パラメータの引き継ぎにnamedを使うのは問題が多い（参考）。代わりにQueryStringを使いたい。 Searchableビヘイビアと同じような内容の $filterArgs を書くのが手間。 そもそも値の検証や制限はモデルでやるべき、と考える。コンポーネント内でバリデーションを実行したりDBアクセスまでするのは仕事のし過ぎ。 これらの点を解消するため、昔作ったSearchPaginationプラグインを全面改訂して、Searchプラグインと連携できるようにしました。Prgコンポーネントの代わりに使うことができます。 http://github.com/tkyk/cakephp-search-pagination （旧版は 1.2 ブランチを参照） 使い方は非常に簡単で、コントローラの中で SearchPagination コンポーネントの setup メソッドを実行するだけです。 class UsersController extends AppController &#123; var $components = array&#40;'SearchPagination.SearchPagination'&#41;; &#160; function search&#40;&#41; &#123; $this-&#62;SearchPagination-&#62;setup&#40;'User'&#41;; //... &#125; &#125; これによってQueryStringから検索パラメータが取得され、data[ModelName] に格納されるので、あとはそれを Searchable ビヘイビアの parseCriteria に渡すなどして、検索条件を組み立てます。 function search&#40;&#41; &#123; $this-&#62;SearchPagination-&#62;setup&#40;'User'&#41;; &#160; // 常に $this-&#62;data['User'] に検索パラメータが入っている &#160; $this-&#62;paginate&#91;'conditions'&#93; = $this-&#62;User-&#62;parseCriteria&#40;$this-&#62;data&#91;'User'&#93;&#41;; [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1378%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2Fb5xycL%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22Search%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AB%E3%82%88%E3%82%8B%E6%A4%9C%E7%B4%A2%E6%9D%A1%E4%BB%B6%E3%82%92%E3%83%9A%E3%83%BC%E3%82%B8%E3%83%B3%E3%82%B0%E3%81%A7%E5%BC%95%E3%81%8D%E7%B6%99%E3%81%90%EF%BC%88Prg%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88%E3%82%8B%EF%BC%89%22%20%7D);"></div>
<p>環境: CakePHP 1.3</p>
<p>
CakeDCの<a href="http://github.com/CakeDC/Search">Searchプラグイン</a>は、全体としては非常に優れたプラグインなのですが、Prgコンポーネントの機能がどうしても私の使い方には合いませんでした。具体的に言うと
</p>
<ul>
<li>検索パラメータの引き継ぎにnamedを使うのは問題が多い（<a href="http://wp.serpere.info/archives/1367">参考</a>）。代わりにQueryStringを使いたい。</li>
<li>Searchableビヘイビアと同じような内容の $filterArgs を書くのが手間。</li>
<li>そもそも値の検証や制限はモデルでやるべき、と考える。コンポーネント内でバリデーションを実行したりDBアクセスまでするのは仕事のし過ぎ。</li>
</ul>
<p>
これらの点を解消するため、昔作ったSearchPaginationプラグインを全面改訂して、Searchプラグインと連携できるようにしました。Prgコンポーネントの代わりに使うことができます。
</p>
<p>
<a href="http://github.com/tkyk/cakephp-search-pagination">http://github.com/tkyk/cakephp-search-pagination</a> （旧版は <a href="http://github.com/tkyk/cakephp-search-pagination/tree/1.2">1.2</a> ブランチを参照）
</p>
<p>
使い方は非常に簡単で、コントローラの中で <code>SearchPagination</code> コンポーネントの <code>setup</code> メソッドを実行するだけです。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> UsersController <span style="color: #000000; font-weight: bold;">extends</span> AppController <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$components</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'SearchPagination.SearchPagination'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">function</span> search<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">SearchPagination</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setup</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">//...</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>



<p>
これによってQueryStringから検索パラメータが取得され、<code>data[ModelName]</code> に格納されるので、あとはそれを <code>Searchable</code> ビヘイビアの <code>parseCriteria</code> に渡すなどして、検索条件を組み立てます。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> search<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">SearchPagination</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setup</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// 常に $this-&gt;data['User'] に検索パラメータが入っている</span>
&nbsp;
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">paginate</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'conditions'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">User</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parseCriteria</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'User'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'users'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">paginate</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'groups'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">User</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Group</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'list'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>



<p>
ビューでは特に何もしなくても自動的に検索パラメータが引き継がれます。普通にFormヘルパーやPaginatorヘルパーを使ってください。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;h2&gt;Search Form&lt;h2&gt;&quot;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">create</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'type'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'get'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">input</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">input</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'created'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">input</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'group_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">end</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Search'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Paginator</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">numbers</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'modulus'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<p>
Formヘルパーのcreateメソッドには、typeとして &#8216;get&#8217; を指定することをおすすめします。もし指定しなかった場合は（Prgコンポーネントに倣って）自動的にGET用URLを生成してリダイレクトされます。
</p>

]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1378/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CakeのURLパラメータに特殊文字を使ってはいけない</title>
		<link>http://wp.serpere.info/archives/1367</link>
		<comments>http://wp.serpere.info/archives/1367#comments</comments>
		<pubDate>Fri, 09 Jul 2010 09:12:31 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1367</guid>
		<description><![CDATA[環境: CakePHP 1.3 CakePHPはURLパラメータのエンコードを一切行わないため、特殊な文字がパラメータに入り込むと容易にルーティングが破綻する。ここで言う「URLパラメータ」とはRoute中に埋め込まれたパラメータ、namedパラメータ、passパラメータのことを指す。 例えば以下のようなRouteがあったとする。 /controller/action/:keyword ここでパラメータkeywordに特殊な文字を与えると… keyword => '%' URL: /controller/action/% 結果: URLとして不正な形式なので"400 Bad Request"になる keyword => '?foo' URL: /controller/action/?foo 結果: ?以降はQueryStringと見なされてルーティングから除外され、Routeにマッチしなくなる keyword => 'a/b/c' URL: /controller/action/a/b/c 結果: /がそのままパラメータ区切りになるのでRouteにマッチしなくなる この問題は単純に rawurlencode/rawurldecode を使うだけでは回避できない。またCakeの設計上の問題なので、簡単な修正方法もない。よって任意の文字が含まれる可能性のあるパラメータをURLに埋め込んではいけない。最も簡単な回避策は、URLパラメータを諦めてQueryStringを使うことである。 Router::url&#40;array&#40;'?' =&#62; array&#40;'keyword' =&#62; $any_characters&#41;&#41;&#41;; 問題の原因と回避策の考察 なぜ rawurlencode で回避できないかというと、CakePHPが mod_rewrite 経由で $_GET['url'] から元のURLを取得しているからだ。 RewriteRule ^(.*)$ index.php?url=$1 [QSA,L] RewriteRuleの後方参照（$1の部分）では%エンコーディングのデコードが行われる。またQueryStringから $_GET に格納される際にもPHPによってデコードが行われる。つまりCakeのルーティングが実行される前に、既に2回のデコードが行われている。よってもしこの問題を rawurlencode で回避するなら、3重に [...]]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1367%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FankpK2%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22Cake%E3%81%AEURL%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%81%AB%E7%89%B9%E6%AE%8A%E6%96%87%E5%AD%97%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84%22%20%7D);"></div>
<p>
環境: CakePHP 1.3
</p>
<p>
CakePHPはURLパラメータのエンコードを<strong>一切</strong>行わないため、特殊な文字がパラメータに入り込むと容易にルーティングが破綻する。ここで言う「URLパラメータ」とはRoute中に埋め込まれたパラメータ、namedパラメータ、passパラメータのことを指す。
</p>
<p>
例えば以下のようなRouteがあったとする。
</p>
<pre>
/controller/action/:keyword
</pre>
<p>
ここでパラメータkeywordに特殊な文字を与えると…
</p>
<pre>
keyword => '%'
URL: /controller/action/%
結果: URLとして不正な形式なので"400 Bad Request"になる
</pre>
<pre>
keyword => '?foo'
URL: /controller/action/?foo
結果: ?以降はQueryStringと見なされてルーティングから除外され、Routeにマッチしなくなる
</pre>
<pre>
keyword => 'a/b/c'
URL: /controller/action/a/b/c
結果: /がそのままパラメータ区切りになるのでRouteにマッチしなくなる
</pre>
<p>
この問題は単純に rawurlencode/rawurldecode を使うだけでは回避できない。またCakeの設計上の問題なので、簡単な修正方法もない。よって<strong>任意の文字が含まれる可能性のあるパラメータをURLに埋め込んではいけない</strong>。最も簡単な回避策は、URLパラメータを諦めてQueryStringを使うことである。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Router<span style="color: #339933;">::</span><span style="color: #004000;">url</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'?'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'keyword'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$any_characters</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<h3>問題の原因と回避策の考察</h3>
<p>
なぜ rawurlencode で回避できないかというと、CakePHPが mod_rewrite 経由で <code>$_GET['url']</code> から元のURLを取得しているからだ。
</p>
<pre>
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</pre>
<p>
<a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriterule">RewriteRule</a>の後方参照（$1の部分）では%エンコーディングのデコードが行われる。またQueryStringから $_GET に格納される際にもPHPによってデコードが行われる。つまりCakeのルーティングが実行される前に、既に2回のデコードが行われている。よってもしこの問題を rawurlencode で回避するなら、3重に rawurlencode した上で rawurldecode しなければならない、ということになる。
</p>
<p>
ちなみに RewriteRule の[B]オプションを指定することで後方参照のデコードを回避することができる。この場合は rawurlencode は2回で済む。しかしそれでもURLが汚くなることは変わりないし、検索エンジンのロボット等もURL中の文字列を認識してくれないだろう。
</p>
<pre>
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L,B]
</pre>
<p>
別の考え方として、%エンコーディング以外の安全なエンコーディングを用いる方法もある。例えば16進数のバイナリ表現に変換すれば、[a-f0-9]しか現れないので確実に安全である。
</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$encoded</span> <span style="color: #339933;">=</span> <span style="color: #990000;">bin2hex</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//[0-9a-f]しか含まれないことを事前にチェックしておくこと</span>
<span style="color: #000088;">$decoded</span> <span style="color: #339933;">=</span> <span style="color: #990000;">pack</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'H*'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$encoded</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>



<p>
ただしこの方法だと長さは元の文字列の2倍になるし、可読性も全く損なわれる。ここまでするくらいならやはりQueryStringを使った方が良いと思う。
</p>
]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1367/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>第2回CakePHP勉強会@福岡 発表資料</title>
		<link>http://wp.serpere.info/archives/1347</link>
		<comments>http://wp.serpere.info/archives/1347#comments</comments>
		<pubDate>Sun, 04 Jul 2010 13:18:32 +0000</pubDate>
		<dc:creator>tkykmw</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://wp.serpere.info/?p=1347</guid>
		<description><![CDATA[7月3日に福岡で開催されたCakePHP勉強会で、『MarkupHelperの紹介および PHPによるDSL実装の可能性について』という題で発表を行いました。以下に資料をアップロードしておきます（右キーで進む、左キーで戻る、上キーでサムネイル表示切り替え）。 資料へのリンク ※Studio ODIN &#8211; 高橋メソッド風 プレゼンスクリプトを使用しています。発表本番では改造版を使ったのですが、ライセンスが不明なので本家のスクリプトに直接リンクを貼っています。 githubのMarkupHelperリポジトリはこちら： http://github.com/tkyk/cakephp-markup-helper 補足 質疑応答より。多少内容を変更しています。 Q. デザイナーに触ってもらうのは難しいのではないか？ A. このヘルパーはもともと「プログラマーがHTMLを書くのを楽にしよう」というコンセプトで作られているため、デザイナーとの連携が必要になる場面では使用できない・使用すべきでないと言えます。（デザインが比較的どうでもいい）内部向けの管理画面、ごく小さなelement、HTMLを生成する別のヘルパーの中、などで使用するのに向いています。 別の言い方をするとコードの分量が HTML > PHP の場合には使う意味は薄いです。コードの分量が PHP >= HTML の場合に威力を発揮します。 Q. XHTML以外のマークアップ言語を作ることはできるか？ A. MarkupHelperは「正しいXHTMLのタグか否か」をチェックしていないので、基本的にはどんなマークアップでも作ることができるはずです。ただし「そのタグが閉じタグを持つか否か」という情報を $emptyElements プロパティ（public）で管理しているので、必要に応じて再定義する必要があります。 Q. ループや条件分岐をメソッドチェーンに組み込めるか？ A.PHP言語の機能的な制約により、不可能です（PHP5.3のクロージャを使えば一応はできるかもしれませんが、書式が煩雑なのでDSLとしては実装できないでしょう）。 ループや条件分岐に相当する処理を入れつつメソッドチェーンを切りたくない場合は、その部分の処理を別のヘルパーのメソッドにまとめて連結することをおすすめします。 $markup->ul->MyHelper_loop_li($arr)->end; …… 勉強会で発表するのが初めてだったので緊張してしまい、発表中は聞いている人の反応を見ている余裕がありませんでした。早口に一気にまくしたててしまったような気がして、理解してもらえたかどうか不安だったのですが、あとで感想を聞くとそれなりに好評だったようでほっとしました。それから高橋メソッドによる大きな文字は、Ustream経由でも見やすかったようです。 勉強会の進行は（いくつか想定外の事態があったにも関わらず）大変スムーズで、気持ちよく発表できました。@k1LoWさんはじめ株式会社Fusicの皆さん、素晴らしい時間をありがとうございました。 福岡は魚もお酒も美味しくて、2次会以降ついつい飲み過ぎてしまいました。酔った勢いで、特に3次会ではずいぶん大口を叩いてしまったような記憶があります…。酔っぱらいの戯言が戯言でなくなるように、もっと精進していこうと思います。]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_jade" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fwp.serpere.info%252Farchives%252F1347%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FbRUr7t%22%2C%20%22style%22%3A%20%22big%22%2C%20%22title%22%3A%20%22%E7%AC%AC2%E5%9B%9ECakePHP%E5%8B%89%E5%BC%B7%E4%BC%9A%40%E7%A6%8F%E5%B2%A1%20%E7%99%BA%E8%A1%A8%E8%B3%87%E6%96%99%22%20%7D);"></div>
<p>
7月3日に福岡で開催されたCakePHP勉強会で、『MarkupHelperの紹介および PHPによるDSL実装の可能性について』という題で発表を行いました。以下に資料をアップロードしておきます（右キーで進む、左キーで戻る、上キーでサムネイル表示切り替え）。
</p>
<p>
<a href="http://www.serpere.info/20100703-cakephp-fukuoka/">資料へのリンク</a><br />
<iframe src="http://www.serpere.info/20100703-cakephp-fukuoka/" scrolling="no"
 style="width:400px; height:250px"></iframe>
</p>
<p>※<a href="http://www.odin.hyork.net/sample/takahashi/">Studio ODIN &#8211; 高橋メソッド風 プレゼンスクリプト</a>を使用しています。発表本番では改造版を使ったのですが、ライセンスが不明なので本家のスクリプトに直接リンクを貼っています。
</p>
<p>
githubのMarkupHelperリポジトリはこちら：<br />
<a href="http://github.com/tkyk/cakephp-markup-helper">http://github.com/tkyk/cakephp-markup-helper</a>
</p>
<h3>補足</h3>
<p>質疑応答より。多少内容を変更しています。</p>
<dl>
<dt>Q. デザイナーに触ってもらうのは難しいのではないか？</dt>
<dd>
A. このヘルパーはもともと「プログラマーがHTMLを書くのを楽にしよう」というコンセプトで作られているため、デザイナーとの連携が必要になる場面では使用できない・使用すべきでないと言えます。（デザインが比較的どうでもいい）内部向けの管理画面、ごく小さなelement、HTMLを生成する別のヘルパーの中、などで使用するのに向いています。</dd>
<dd>別の言い方をするとコードの分量が HTML > PHP の場合には使う意味は薄いです。コードの分量が PHP >= HTML の場合に威力を発揮します。
</dd>
<dt>Q. XHTML以外のマークアップ言語を作ることはできるか？</dt>
<dd>
A. MarkupHelperは「正しいXHTMLのタグか否か」をチェックしていないので、基本的にはどんなマークアップでも作ることができるはずです。ただし「そのタグが閉じタグを持つか否か」という情報を $emptyElements プロパティ（public）で管理しているので、必要に応じて再定義する必要があります。
</dd>
<dt>Q. ループや条件分岐をメソッドチェーンに組み込めるか？</dt>
<dd>
A.PHP言語の機能的な制約により、不可能です（PHP5.3のクロージャを使えば一応はできるかもしれませんが、書式が煩雑なのでDSLとしては実装できないでしょう）。</dd>
<dd>ループや条件分岐に相当する処理を入れつつメソッドチェーンを切りたくない場合は、その部分の処理を別のヘルパーのメソッドにまとめて連結することをおすすめします。 <br />
<code>$markup->ul->MyHelper_loop_li($arr)->end;</code></dd>
</dl>
<p>
……
</p>
<p>
勉強会で発表するのが初めてだったので緊張してしまい、発表中は聞いている人の反応を見ている余裕がありませんでした。早口に一気にまくしたててしまったような気がして、理解してもらえたかどうか不安だったのですが、あとで感想を聞くとそれなりに好評だったようでほっとしました。それから高橋メソッドによる大きな文字は、Ustream経由でも見やすかったようです。
</p>
<p>
勉強会の進行は（いくつか想定外の事態があったにも関わらず）大変スムーズで、気持ちよく発表できました。@k1LoWさんはじめ株式会社Fusicの皆さん、素晴らしい時間をありがとうございました。
</p>
<p>
福岡は魚もお酒も美味しくて、2次会以降ついつい飲み過ぎてしまいました。酔った勢いで、特に3次会ではずいぶん大口を叩いてしまったような記憶があります…。酔っぱらいの戯言が戯言でなくなるように、もっと精進していこうと思います。
</p>

]]></content:encoded>
			<wfw:commentRss>http://wp.serpere.info/archives/1347/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

