<?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>@blog.justoneplanet.info &#187; PHP</title>
	<atom:link href="http://blog.justoneplanet.info/category/computer-language/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.justoneplanet.info</link>
	<description>日々勉強</description>
	<lastBuildDate>Wed, 08 Feb 2012 02:57:17 +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>PHPで不正な閉じタグを見つける</title>
		<link>http://blog.justoneplanet.info/2012/02/04/php%e3%81%a7%e4%b8%8d%e6%ad%a3%e3%81%aa%e9%96%89%e3%81%98%e3%82%bf%e3%82%b0%e3%82%92%e8%a6%8b%e3%81%a4%e3%81%91%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2012/02/04/php%e3%81%a7%e4%b8%8d%e6%ad%a3%e3%81%aa%e9%96%89%e3%81%98%e3%82%bf%e3%82%b0%e3%82%92%e8%a6%8b%e3%81%a4%e3%81%91%e3%82%8b/#comments</comments>
		<pubDate>Sat, 04 Feb 2012 11:10:47 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=5000</guid>
		<description><![CDATA[ループは1回にできると思うけどまぁとりあえず。 &#60;?php $str = &#60;&#60;&#60;EOD &#60;html&#62; &#60;body&#62; &#60;center&#62; &#60;form acti [...]]]></description>
			<content:encoded><![CDATA[<p>ループは1回にできると思うけどまぁとりあえず。</p>
<pre class="brush: php;">
&lt;?php
$str = &lt;&lt;&lt;EOD
&lt;html&gt;
&lt;body&gt;
&lt;center&gt;
&lt;form action=&quot;confirm.php&quot; method=&quot;get&quot;&gt;
&lt;input type=&quot;text&quot; name=&quot;name&quot;&gt;&lt;br&gt;
&lt;input type=&quot;submit&quot; value=&quot;submit&quot;&gt;
&lt;/center&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
EOD;

preg_match_all(&quot;/&lt;.*?&gt;/&quot;, $str, $matches);
//var_dump($matches);
$ary = array();
$stack = array();

foreach ($matches[0] as $key =&gt; $value) {
    array_push($ary, $value);
}

foreach ($ary as $key =&gt; $value) {
    if (preg_match(&quot;/&lt;\/([a-zA-Z]+)/&quot;, $value, $tag)) {
#        echo &quot;$value\n&quot;;
#        var_dump($tag[1]);
        $isFoundClose = false;
        foreach ($ary as $k =&gt; $v) {
            if (preg_match(&quot;/&lt;{$tag[1]}/&quot;, $v)) {
#                echo &quot;match\n&quot;;
                $isFoundClose = true;
                array_splice($ary, $k, $key - $k);
                break;
            }
        }
        if (!$isFoundClose) {
            echo &quot;error:$value\n&quot;;
        }
    }
    else {

    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2012/02/04/php%e3%81%a7%e4%b8%8d%e6%ad%a3%e3%81%aa%e9%96%89%e3%81%98%e3%82%bf%e3%82%b0%e3%82%92%e8%a6%8b%e3%81%a4%e3%81%91%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP 2.0.4で多言語対応する</title>
		<link>http://blog.justoneplanet.info/2011/12/23/cakephp%e3%81%a7%e5%a4%9a%e8%a8%80%e8%aa%9e%e5%af%be%e5%bf%9c%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/12/23/cakephp%e3%81%a7%e5%a4%9a%e8%a8%80%e8%aa%9e%e5%af%be%e5%bf%9c%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 14:27:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4871</guid>
		<description><![CDATA[■手順 アプリケーションのrootディレクトリで以下のコマンドを実行する。 php lib/Cake/Console/cake.php i18n 以下のように表示される。 Welcome to CakePHP v2.0. [...]]]></description>
			<content:encoded><![CDATA[<h3>■手順</h3>
<p>アプリケーションのrootディレクトリで以下のコマンドを実行する。</p>
<pre class="brush: bash;">
php lib/Cake/Console/cake.php i18n
</pre>
<p>以下のように表示される。</p>
<pre class="brush: bash;">
Welcome to CakePHP v2.0.4 Console
---------------------------------------------------------------
App : app
Path: /var/www/domain/app/
---------------------------------------------------------------
I18n Shell
---------------------------------------------------------------
[E]xtract POT file from sources
[I]nitialize i18n database table
[H]elp
[Q]uit
What would you like to do? (E/I/H/Q)
</pre>
<p>Eを選択する。</p>
<pre class="brush: bash;">
What is the path you would like to extract?
[Q]uit [D]one
[/var/www/domain/app/] &gt;
</pre>
<p>Dを選択する。</p>
<pre class="brush: bash;">
What is the path you would like to output?
[Q]uit
[/var/www/domain/app//Locale] &gt;
Would you like to merge all domains strings into the default.pot file? (y/n)
</pre>
<p>yを選択すると、ファイルを読み込んでデフォルトの言語ファイルが生成される。</p>
<ul>
<li>/var/www/domain/app/Locale/default.pot</li>
<li>/var/www/domain/app/Locale/eng</li>
</ul>
<p>/var/www/domain/app/Locale/engをコピーして/var/www/domain/app/Locale/jpnを作り、/var/www/domain/app/Locale/default.potをコピーして、/var/www/domain/app/Locale/jpn/LC_MESSAGES/default.poを作る。この時、拡張子を変更しないと上手く動作しない。</p>
<h4>翻訳ファイル</h4>
<p>翻訳ファイルは以下のように記述する。</p>
<pre class="brush: bash;">
#: Controller/HogeController.php:65;166;188;214
msgid &quot;Hello world&quot;
msgstr &quot;世界こんにちわ&quot;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/12/23/cakephp%e3%81%a7%e5%a4%9a%e8%a8%80%e8%aa%9e%e5%af%be%e5%bf%9c%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP 2.0でログインフォームを作る</title>
		<link>http://blog.justoneplanet.info/2011/11/13/cakephp-2-0%e3%81%a7%e3%83%ad%e3%82%b0%e3%82%a4%e3%83%b3%e3%83%95%e3%82%a9%e3%83%bc%e3%83%a0%e3%82%92%e4%bd%9c%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/11/13/cakephp-2-0%e3%81%a7%e3%83%ad%e3%82%b0%e3%82%a4%e3%83%b3%e3%83%95%e3%82%a9%e3%83%bc%e3%83%a0%e3%82%92%e4%bd%9c%e3%82%8b/#comments</comments>
		<pubDate>Sun, 13 Nov 2011 08:46:47 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4767</guid>
		<description><![CDATA[■実装 app/Controller/UsersController.php App::uses('AppController', 'Controller'); /** * Users Controller * @pro [...]]]></description>
			<content:encoded><![CDATA[<h3>■実装</h3>
<h4>app/Controller/UsersController.php</h4>
<pre class="brush: php;">
App::uses('AppController', 'Controller');
/**
 * Users Controller
 * @property User $User
 */
class UsersController extends AppController {

    public $uses = array('User');

    public $components = array(
        'Session',
        'Auth' =&gt; array(
            'loginRedirect' =&gt; array('controller'  =&gt; 'users', 'action' =&gt; 'index'),// ログイン後のリダイレクト先
            'logoutRedirect' =&gt; array('controller' =&gt; 'pages', 'action' =&gt; 'display', 'home')// ログアウト後のリダイレクト先
        )
    );

    public function beforeFilter() {
        //$this-&gt;Auth-&gt;allow('index'/*, 'add'*/);// 認証を除外するアクションを指定する
    }

    /**
     * ユーザを追加する画面
     * @return void
     */
    public function add() {
        /*if ($this-&gt;request-&gt;is('post')) {
            $this-&gt;User-&gt;create();
            if ($this-&gt;User-&gt;save($this-&gt;request-&gt;data)) {
                $this-&gt;Session-&gt;setFlash(__('The user has been saved'));
                $this-&gt;redirect(array('action' =&gt; 'index'));
            }
            else {
                $this-&gt;Session-&gt;setFlash(__('The user could not be saved. Please, try again.'));
            }
        }*/
    }

    /**
     * ログイン画面
     * @return void
     */
    public function admin_login() {
        if ($this-&gt;Auth-&gt;login()) {
            $this-&gt;redirect($this-&gt;Auth-&gt;redirect());
        }
        else {
            $this-&gt;Session-&gt;setFlash(__('Invalid username or password, try again'));
        }
    }

    /**
     * ログアウト画面
     * @return void
     */
    public function admin_logout() {
        $this-&gt;redirect($this-&gt;Auth-&gt;logout());
    }
}
</pre>
<h4>app/Model/User.php</h4>
<pre class="brush: php;">
App::uses('AppModel', 'Model');

/**
 * User Model
 * ユーザのモデル
 */
class User extends AppModel {
    public function __construct($id = false, $table = null, $ds = null) {
        $this-&gt;useDbConfig = Configure::read('Config.environment');
        parent::__construct($id, $table, $ds);
    }

    /**
     * 保存前に実行される
     * @return void
     */
    public function beforeSave() {
        if (isset($this-&gt;data[$this-&gt;alias]['password'])) {
            $this-&gt;data[$this-&gt;alias]['password'] = AuthComponent::password($this-&gt;data[$this-&gt;alias]['password']);
        }
        return true;
    }

}
</pre>
<p>Cake1系ではpasswordというカラム名が自動的にハッシュ化されていた。Cake2系では上述のように実装する必要がある。</p>
<h4>app/View/Users/admin_login.ctp</h4>
<p>以下のようにログインフォームを記述する。</p>
<pre class="brush: php;">
&lt;?php echo $this-&gt;Session-&gt;flash('auth'); ?&gt;
&lt;?php echo $this-&gt;Form-&gt;create('User');?&gt;
&lt;fieldset&gt;
&lt;legend&gt;&lt;?php echo __('Please enter your username and password'); ?&gt;&lt;/legend&gt;
&lt;?php
echo $this-&gt;Form-&gt;input('username');
echo $this-&gt;Form-&gt;input('password');
?&gt;
&lt;/fieldset&gt;
&lt;?php echo $this-&gt;Form-&gt;end(__('Login'));?&gt;
</pre>
<p>$thisを介してSessionとFormにアクセスするところがCake2系では異なる。</p>
<h4>app/View/Users/admin_logout.ctp</h4>
<pre class="brush: php;">
&lt;h3&gt;ログアウトしました。&lt;/h3&gt;
</pre>
<h3>■参考</h3>
<ul>
<li><a href="http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html">Simple Authentication and Authorization Application</a></li>
<li><a href="http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html">Authentication</a></li>
</ul>
<p>殆ど参考文献の簡略化日本語版だな。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/11/13/cakephp-2-0%e3%81%a7%e3%83%ad%e3%82%b0%e3%82%a4%e3%83%b3%e3%83%95%e3%82%a9%e3%83%bc%e3%83%a0%e3%82%92%e4%bd%9c%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP2.0でPHPUnitを使う</title>
		<link>http://blog.justoneplanet.info/2011/09/21/cakephp2-0%e3%81%a7phpunit%e3%82%92%e4%bd%bf%e3%81%86/</link>
		<comments>http://blog.justoneplanet.info/2011/09/21/cakephp2-0%e3%81%a7phpunit%e3%82%92%e4%bd%bf%e3%81%86/#comments</comments>
		<pubDate>Tue, 20 Sep 2011 15:56:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4563</guid>
		<description><![CDATA[めも。 ■PHPUnitのインストール 以下のコマンドでXAMPP for MacでPHPUnitが使えるようになる。 sudo /Applications/XAMPP/xamppfiles/bin/pear chann [...]]]></description>
			<content:encoded><![CDATA[<p>めも。</p>
<h3>■PHPUnitのインストール</h3>
<p>以下のコマンドでXAMPP for MacでPHPUnitが使えるようになる。</p>
<pre class="brush: bash;">
sudo /Applications/XAMPP/xamppfiles/bin/pear channel-update pear.php.net
sudo /Applications/XAMPP/xamppfiles/bin/pear upgrade pear
sudo /Applications/XAMPP/xamppfiles/bin/pear channel-discover pear.phpunit.de
sudo /Applications/XAMPP/xamppfiles/bin/pear channel-discover pear.symfony-project.com
sudo /Applications/XAMPP/xamppfiles/bin/pear channel-discover components.ez.no
sudo /Applications/XAMPP/xamppfiles/bin/pear install phpunit/PHPUnit
</pre>
<p>詳しくは<a href="/?p=3379">以前の記事</a>で。</p>
<h3>■Bake</h3>
<section class="kakomi">
<h4>PHPのエラー</h4>
<p>お決まりのtimezoneを設定してくれ的なのが出るので以下のようにする。</p>
<pre class="brush: bash;">
vim ./lib/Cake/Console/cake.php
</pre>
<p>require_onceの前に以下の文を一応記述しておく。</p>
<pre class="brush: php;">
ini_set('date.timezone', 'Asia/Tokyo');
</pre>
</section>
<h4>データベースの初期設定</h4>
<p>以下のコマンドを実行してDBの設定をする。</p>
<pre class="brush: bash;">
./lib/Cake/Console/cake.php bake
</pre>
<p>対話式ですすめる。以下の順序で設定する。</p>
<pre class="brush: bash;">
Welcome to CakePHP v2.0.0 Console
---------------------------------------------------------------
App : app
Path: /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/
---------------------------------------------------------------
Your database configuration was not found. Take a moment to create one.
---------------------------------------------------------------
Database Configuration:
---------------------------------------------------------------
Name:
[default] &gt; test
Driver: (Mysql/Postgres/Sqlite/Sqlserver)
[Mysql] &gt;
Persistent Connection? (y/n)
[n] &gt;
Database Host:
[localhost] &gt;
Port?
[n] &gt;
User:
[root] &gt;
Password:
&gt; hogehoge
Database Name:
[cake] &gt; dbname
Table Prefix?
[n] &gt;
Table encoding?
[n] &gt;
</pre>
<h4>モデル（クラス）の作成</h4>
<p>以下のコマンドを再度実行する。</p>
<pre class="brush: bash;">
./lib/Cake/Console/cake.php bake
</pre>
<p>以下のように進めていく。テーブル設計などは適当なので適宜読み替える。</p>
<pre class="brush: bash;">
---------------------------------------------------------------
App : app
Path: /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[F]ixture
[T]est case
[Q]uit
What would you like to Bake? (D/M/V/C/P/F/T/Q)
&gt; Model
What would you like to Bake? (D/M/V/C/P/F/T/Q)
&gt; M
---------------------------------------------------------------
Bake Model
Path: /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/Model/
---------------------------------------------------------------
Possible Models based on your current database:
1. Move
Enter a number from the list above,
type in the name of another model, or 'q' to exit
[q] &gt; 1
A displayField could not be automatically detected
would you like to choose one? (y/n)
&gt; y
1. id
2. game
3. x
4. y
5. color
Choose a field from the options above:
&gt; 1
Would you like to supply validation criteria
for the fields in your model? (y/n)
[y] &gt; y
</pre>
<p>バリデーションの設定をしていくと、そのうち以下のようにユニットテスト用ファイルを生成するか聞いてくるので[y]を選択する。</p>
<pre class="brush: bash;">
Do you want to bake unit test files anyway? (y/n)
[y] &gt; y
Creating file /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/Test/Case/Model/MoveTest.php
Wrote `/Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/Test/Case/Model/MoveTest.php`
</pre>
<h3>■生成されたファイル</h3>
<h4>app/Test/Case/Model/MoveTestCase.php</h4>
<pre class="brush: php;">
&lt;?php
/* Move Test cases generated on: 2011-10-21 00:40:13 : 1319125213*/
App::uses('Move', 'Model');

/**
 * Move Test Case
 *
 */
class MoveTestCase extends CakeTestCase {
/**
 * Fixtures
 *
 * @var array
 */
    public $fixtures = array('app.move');

/**
 * setUp method
 *
 * @return void
 */
    public function setUp() {
        parent::setUp();

        $this-&gt;Move = ClassRegistry::init('Move');
    }

/**
 * tearDown method
 *
 * @return void
 */
    public function tearDown() {
        unset($this-&gt;Move);

        parent::tearDown();
    }

/**
 * こんな感じで書いていけばいいよ的なmethod
 */
    public function testGetById() {
        $this-&gt;assertEqual($this-&gt;Move-&gt;getById(1), 1);
    }
}
</pre>
<h4>app/Model/MoveTestCase.php</h4>
<pre class="brush: php;">
&lt;?php
App::uses('AppModel', 'Model');
/**
 * Move Model
 *
 */
class Move extends AppModel {
/**
 * Display field
 *
 * @var string
 */
    public $displayField = 'id';

/**
 * つじつま合わせのメソッド
 */
    public function getById($id) {
        return 1;
    }
}
</pre>
<p>最後にちゃちゃっとhttp://cake.sample.justoneplanet.info/test.phpにアクセスすればテストが書けているのがわかる。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/09/21/cakephp2-0%e3%81%a7phpunit%e3%82%92%e4%bd%bf%e3%81%86/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>crontabとCakePHPでバッチ処理をする</title>
		<link>http://blog.justoneplanet.info/2011/08/14/crontab%e3%81%a8cakephp%e3%81%a7%e3%83%90%e3%83%83%e3%83%81%e5%87%a6%e7%90%86%e3%82%92%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/08/14/crontab%e3%81%a8cakephp%e3%81%a7%e3%83%90%e3%83%83%e3%83%81%e5%87%a6%e7%90%86%e3%82%92%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Sun, 14 Aug 2011 12:50:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4300</guid>
		<description><![CDATA[バッチ処理したい時などに使う技である。 ■実装 app/vendors/shells/calc.php 以下のようにしてShellクラスを継承する。基本的にはコントローラと同様にモデルなどが使用できるがコンポーネントにつ [...]]]></description>
			<content:encoded><![CDATA[<p>バッチ処理したい時などに使う技である。</p>
<h3>■実装</h3>
<h4>app/vendors/shells/calc.php</h4>
<p>以下のようにしてShellクラスを継承する。基本的にはコントローラと同様にモデルなどが使用できるがコンポーネントについては注意が必要である。</p>
<pre class="brush: php;">
date_default_timezone_set('Asia/Tokyo');

//Configure::write('Config.environment', isset($_SERVER['CAKE_ENV']) ? $_SERVER['CAKE_ENV'] : &quot;development&quot;);// コマンドラインから叩いている場合、$_SERVERによる環境分岐ができない
Configure::write('Config.environment', &quot;production&quot;);

class RankShell extends Shell
{
    public $uses = array(
        'Logs',
        'Ranks'
    );

    /**
     * 処理を実行する前に読み込むコンポーネントなどを記述する
     */
    public function initialize()
    {
        parent::initialize();
        //$this-&gt;Email = new EmailComponent($this);// コンポーネント名に注意
    }

    /**
     * ここに記述した処理が実行される
     */
    public function main()
    {
        $this-&gt;out(&quot;start&quot;);
        if($result = $this-&gt;Log-&gt;getRank()){
            $this-&gt;Ranks-&gt;deleteAll();
            if($this-&gt;Ranks-&gt;saveAll($result)){
                $this-&gt;out(&quot;success&quot;);
            }
            else{
                $this-&gt;out(&quot;failed to save&quot;);
            }
        }
        else{
            $this-&gt;out(&quot;failed to calc&quot;);
        }
    }
}
</pre>
<h3>■実行</h3>
<p>以下のようにして実行できるかどうか確認する。</p>
<pre class="brush: bash;">
/usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
</pre>
<h3>■crontab</h3>
<p>以下のコマンドを実行してcrontabを編集する。</p>
<pre class="brush: bash;">
crontab -e
</pre>
<p>例えば10時のオヤツを忘れないよう10:15に実行するようにするには以下のようにする。</p>
<pre class="brush: bash;">
15 10 * * * /usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
</pre>
<p>15分ごとに処理をするには以下のように記述する。</p>
<pre class="brush: bash;">
*/15 * * * * /usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
</pre>
<p>以上のようにCakePHPでは非常に簡単にバッチ処理を書くことができる。個人的にはZendFrameworkよりも簡単に感じる。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/08/14/crontab%e3%81%a8cakephp%e3%81%a7%e3%83%90%e3%83%83%e3%83%81%e5%87%a6%e7%90%86%e3%82%92%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPのrenderメソッドでViewファイルを指定する</title>
		<link>http://blog.justoneplanet.info/2011/08/08/cakephp%e3%81%aerender%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89%e3%81%a7view%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%92%e6%8c%87%e5%ae%9a%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/08/08/cakephp%e3%81%aerender%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89%e3%81%a7view%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%92%e6%8c%87%e5%ae%9a%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Mon, 08 Aug 2011 14:00:27 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4273</guid>
		<description><![CDATA[以下のように指定することも多々ある。 $this-&#62;render('/ajax/json'); Cake内部でファイルを探索する際、open_basedirの制限に引っかかることがあるので以下のように記述すると良い [...]]]></description>
			<content:encoded><![CDATA[<p>以下のように指定することも多々ある。</p>
<pre class="brush: php;">
$this-&gt;render('/ajax/json');
</pre>
<p>Cake内部でファイルを探索する際、open_basedirの制限に引っかかることがあるので以下のように記述すると良い。</p>
<pre class="brush: php;">
$this-&gt;render(null, null, VIEWS . 'ajax' . DS . 'json.ctp');
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/08/08/cakephp%e3%81%aerender%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89%e3%81%a7view%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%92%e6%8c%87%e5%ae%9a%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPでモデルを作る</title>
		<link>http://blog.justoneplanet.info/2011/07/20/cakephp%e3%81%a7%e3%83%a2%e3%83%87%e3%83%ab%e3%82%92%e4%bd%9c%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/07/20/cakephp%e3%81%a7%e3%83%a2%e3%83%87%e3%83%ab%e3%82%92%e4%bd%9c%e3%82%8b/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 17:42:33 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4185</guid>
		<description><![CDATA[前回に引き続き今更ではあるがメモっておく。 ■モデルのファイル生成 bakeする bakeの前に解説用に以下のテーブルを作る。 CREATE TABLE `users` ( `id` int(10) NOT NULL A [...]]]></description>
			<content:encoded><![CDATA[<p>前回に引き続き今更ではあるがメモっておく。</p>
<h3>■モデルのファイル生成</h3>
<h4>bakeする</h4>
<p>bakeの前に解説用に以下のテーブルを作る。</p>
<pre class="brush: plain;">
CREATE TABLE `users` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `is_public` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
</pre>
<p>以下のコマンドを実行する。</p>
<pre class="brush: plain;">
./cake/console/cake bake
</pre>
<p>以下のように表示される。</p>
<pre class="brush: plain;">
Welcome to CakePHP v1.3.10 Console
---------------------------------------------------------------
App : app
Path: /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[F]ixture
[T]est case
[Q]uit
What would you like to Bake? (D/M/V/C/P/F/T/Q)
&gt; M
</pre>
<p>Mを選択すると以下の選択肢が表示されるのでdefaultを選択する。</p>
<pre class="brush: plain;">
---------------------------------------------------------------
Bake Model
Path: /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/models/
---------------------------------------------------------------
Use Database Config: (default/production)
[default] &gt; default
</pre>
<section class="kakomi">
<p>この時点でDBにテーブルが存在していないと以下のように表示される。</p>
<pre class="brush: plain;">
Your database does not have any tables.
</pre>
<p>当然だけどデータストアの定義がされていないのにコードを書き始めてはいけない。</p>
</section>
<p>テーブルが存在している場合は以下のように表示される。</p>
<pre class="brush: plain;">
Possible Models based on your current database:
1. User
Enter a number from the list above,
type in the name of another model, or 'q' to exit
</pre>
<p>1番を選択すると以下のように質問される。</p>
<pre class="brush: plain;">
Would you like to supply validation criteria
for the fields in your model? (y/n)
</pre>
<p>yを選択すると以下のように表示される。</p>
<pre class="brush: plain;">
Field: id
Type: integer
---------------------------------------------------------------
Please select one of the following validation options:
---------------------------------------------------------------
1 - alphanumeric
2 - between
3 - blank
4 - boolean
5 - cc
6 - comparison
7 - custom
8 - date
9 - decimal
10 - email
11 - equalto
12 - extension
13 - inlist
14 - ip
15 - maxlength
16 - minlength
17 - money
18 - multiple
19 - notempty
20 - numeric
21 - phone
22 - postal
23 - range
24 - ssn
25 - time
26 - url
27 - userdefined
28 - uuid
29 - Do not do any validation on this field.
</pre>
<p>どんな入力値チェックをするかという事ですな。ここで設定した値を元にソースを書きだしてくれる。但し、idはautoincrementで特にinsertするカラムではないので29を選択する。</p>
<pre class="brush: plain;">
Field: name
Type: string
---------------------------------------------------------------
Please select one of the following validation options:
---------------------------------------------------------------
1 - alphanumeric
2 - between
3 - blank
4 - boolean
5 - cc
6 - comparison
7 - custom
8 - date
9 - decimal
10 - email
11 - equalto
12 - extension
13 - inlist
14 - ip
15 - maxlength
16 - minlength
17 - money
18 - multiple
19 - notempty
20 - numeric
21 - phone
22 - postal
23 - range
24 - ssn
25 - time
26 - url
27 - userdefined
28 - uuid
29 - Do not do any validation on this field.
... or enter in a valid regex validation string.
</pre>
<p>次に表示されるのはnameカラムに対するバリデーションだ。必須項目としたいので19を入力すると以下のように表示される。</p>
<pre class="brush: plain;">
Would you like to add another validation rule? (y/n)
</pre>
<p>1つのカラムに複数のバリデーションを適用できるので必要な場合は番号を入力する。次はパスワードだ。</p>
<pre class="brush: plain;">
Field: password
Type: string
---------------------------------------------------------------
Please select one of the following validation options:
---------------------------------------------------------------
1 - alphanumeric
2 - between
3 - blank
4 - boolean
5 - cc
6 - comparison
7 - custom
8 - date
9 - decimal
10 - email
11 - equalto
12 - extension
13 - inlist
14 - ip
15 - maxlength
16 - minlength
17 - money
18 - multiple
19 - notempty
20 - numeric
21 - phone
22 - postal
23 - range
24 - ssn
25 - time
26 - url
27 - userdefined
28 - uuid
29 - Do not do any validation on this field.
... or enter in a valid regex validation string.

[19] &gt;
</pre>
<p>1と19あたりを設定すると思う。次はemailだ。</p>
<pre class="brush: plain;">
Field: email
Type: string
---------------------------------------------------------------
Please select one of the following validation options:
---------------------------------------------------------------
1 - alphanumeric
2 - between
3 - blank
4 - boolean
5 - cc
6 - comparison
7 - custom
8 - date
9 - decimal
10 - email
11 - equalto
12 - extension
13 - inlist
14 - ip
15 - maxlength
16 - minlength
17 - money
18 - multiple
19 - notempty
20 - numeric
21 - phone
22 - postal
23 - range
24 - ssn
25 - time
26 - url
27 - userdefined
28 - uuid
29 - Do not do any validation on this field.
... or enter in a valid regex validation string.

[10] &gt;
</pre>
<p>なんとカラム名から判断して10番を提示してくれるではないか。Cakeは気がきくのだがこれは時としてお節介にもなる。そんなこんなでバリデーションを設定していくと次に以下のような質問をされる。</p>
<pre class="brush: bash;">
Would you like to define model associations
(hasMany, hasOne, belongsTo, etc.)? (y/n)
</pre>
<p>関連するテーブルを聞かれているのだが、まだ他のテーブル存在していないのでnを入力する。</p>
<pre class="brush: bash;">
---------------------------------------------------------------
The following Model will be created:
---------------------------------------------------------------
Name:       User
DB Table:   `users`
Validation: Array
(
    [name] =&gt; Array
        (
            [notempty] =&gt; notempty
        )

    [password] =&gt; Array
        (
            [notempty] =&gt; notempty
        )

    [email] =&gt; Array
        (
            [email] =&gt; email
        )

    [is_public] =&gt; Array
        (
            [boolean] =&gt; boolean
        )

)

-------------------------
</pre>
<p>上述のように生成されるファイルの確認をされるのでyを押す。</p>
<section class="kakomi">
<p>ファイルが存在している場合は上書きの確認メッセージが表示される。</p>
<pre class="brush: bash;">
Creating file /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/models/user.php
File `/Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/models/user.php` exists, overwrite? (y/n/q)
[n] &gt;
</pre>
</section>
<p>次に単体テスト用のファイルをbakeするか聞かれる。</p>
<pre class="brush: bash;">
SimpleTest is not installed. Do you want to bake unit test files anyway? (y/n)
</pre>
<p>やっぱちゃんとたりたいのでyを選択する。ちなみにSimpleTestのインストールは後からでも全然構わない。ファイルは「./app/tests/cases/models/user.test.php」に自動的に生成されている。</p>
<h3>■生成したファイル</h3>
<h4>./app/models/user.php</h4>
<pre class="brush: php;">
&lt;?php
class User extends AppModel {
    var $name = 'User';
    var $displayField = 'name';
    var $validate = array(
        'name' =&gt; array(
            'notempty' =&gt; array(
                'rule' =&gt; array('notempty'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
        'password' =&gt; array(
            'notempty' =&gt; array(
                'rule' =&gt; array('notempty'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
        'email' =&gt; array(
            'email' =&gt; array(
                'rule' =&gt; array('email'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
        'is_public' =&gt; array(
            'boolean' =&gt; array(
                'rule' =&gt; array('boolean'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
    );
}
</pre>
<p>コメントアウトされている部分については一番上を参考にする。</p>
<h4>./app/tests/cases/models/user.test.php</h4>
<pre class="brush: php;">
/* User Test cases generated on: 2011-07-20 02:35:04 : 1311096904*/
App::import('Model', 'User');

class UserTestCase extends CakeTestCase {
	var $fixtures = array('app.user');

	function startTest() {
		$this-&gt;User =&amp; ClassRegistry::init('User');
	}

	function endTest() {
		unset($this-&gt;User);
		ClassRegistry::flush();
	}

}
</pre>
<p>しかし、PHP5の文法で書きだして欲しいかつインデントはスペースを使って欲しいものだ。</p>
<h3>■SimpleTest</h3>
<p>debugモードで動作しているサイトのtest.phpにアクセスするとSimpleTestがダウンロードされていない場合、<a href="http://simpletest.org/en/download.html">リンク</a>が表示されるのでそこからダウンロードする。。。のもいいんだが分かりにくいのでコマンドラインから操作する。</p>
<pre class="brush: bash;">
cd vendors
wget http://sourceforge.net/projects/simpletest/files/simpletest/simpletest_1.0.1/simpletest_1.0.1.tar.gz/download
tar xvzf simpletest_1.0.1.tar.gz
rm simpletest_1.0.1.tar.gz
</pre>
<p>上述の操作でSimpleTestが使用できるようになった。テストケースについてはまた別の機会に解説する。</p>
<h4>eclipseプラグイン</h4>
<p>eclipseプラグインもあるのだがデバッグの構成とかいまいち設定方法が分からん。。。</p>
<h3>■メソッドの記述</h3>
<p>モデルクラスができたので試しにidからユーザを取得するメソッドgetByIdを書いてみる。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    public $displayField = 'name';
    public $validate = array(
        'name' =&gt; array(
            'notempty' =&gt; array(
                'rule' =&gt; array('notempty'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
        'password' =&gt; array(
            'notempty' =&gt; array(
                'rule' =&gt; array('notempty'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
        'email' =&gt; array(
            'email' =&gt; array(
                'rule' =&gt; array('email'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
        'is_public' =&gt; array(
            'boolean' =&gt; array(
                'rule' =&gt; array('boolean'),
                //'message' =&gt; 'Your custom message here',
                //'allowEmpty' =&gt; false,
                //'required' =&gt; false,
                //'last' =&gt; false, // Stop validation after this rule
                //'on' =&gt; 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
    );

    /**
     * getById
     *
     * @param numeric $id
     */
    public function getById($id)
    {
        $id = (int) $id;
        $result = $this-&gt;find(
            'first',
            array(
                'conditions' =&gt; array(
                    'id' =&gt; $id
                )
            )
        );
        return $result;
    }
}
</pre>
<p>SQLは見当たらない。生のSQLを書かないのが流儀である。まぁ、サブクエリとか書くときは普通に生で書いちゃうんだけど・・・少なくとも通常のCRUDはORMを使うべきだと思う。</p>
<h4>理由</h4>
<p><a href="http://symfony.xrea.jp/1.1/book/08-Inside-the-Model-Layer.html#why.use.an.orm.and.an.abstraction.layer">Symfonyの記事</a>を参考に読んだ。以下は抜粋である。</p>
<blockquote><p>データベースはリレーショナルです。一方でPHP 5とsymfonyはオブジェクト指向です。オブジェクト指向のコンテキストでもっとも効果的にデータベースにアクセスするには、オブジェクトをリレーショナルなロジックに変換するインターフェイスが求められます。</p></blockquote>
<p>リレーショナルから取り出すものは単なるデータの集合に過ぎないが、オブジェクトを取り出せるならコードとの相性もいいよね。</p>
<pre class="brush: php;">
$data = &quot;{'name' : 'pochi' , 'age' : 28}&quot;;
$data = new Dog('pochi', 28);
$data-&gt;cry();// こんな感じ
</pre>
<blockquote><p>抽象化レイヤーの主な利点は、移植性です。これによって、プロジェクトの真っ最中でも、別のデータベースに切り替えることができます。</p></blockquote>
<p>そう！DBに依存した部分の変換（泥臭い仕事）はフレームワークがこなす。しかし、プロジェクトの途中でDBが変わるなんてあるのか・・・？</p>
<h4>例</h4>
<p>詳しくはドキュメントを参照するのが良いんだが、まぁとりあえず書いてみる。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * getByAge
     * 年齢でユーザを検索する
     * @param numeric $age
     */
    public function getByAge($age)
    {
        $age = (int) $age;
        $result = $this-&gt;find(
            'all',
            array(
                'conditions' =&gt; array(
                    'age' =&gt; $age
                )
            )
        );
        return $result;
    }
}
</pre>
<p>前述と違うのは結果が複数あるのでallを使用した。条件が複数ある場合は以下のようにする。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * getByAgeAndGender
     * 年齢と性別でユーザを検索する
     * @param numeric $age
     * @param numeric $gender
     */
    public function getByAgeAndGender($age , $gender)
    {
        $age    = (int) $age;
        $gender = (int) $gender;
        $result = $this-&gt;find(
            'all',
            array(
                'conditions' =&gt; array(
                    'age'    =&gt; $age,
                    'gender' =&gt; $gender,
                )
            )
        );
        return $result;
    }
}
</pre>
<p>上述のように配列の要素を増やすだけで良い。</p>
<section class="kakomi">
<h5>範囲</h5>
<p>日付や数値などで等号ではなく大なり小なりを指定して特定の範囲に含まれるレコードが欲しい場合がある。以下のようにすると実現できる。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * getByAgeRangeAndGender
     * 年齢の範囲と性別でユーザを検索する
     * @param numeric $minAge
     * @param numeric $maxAge
     * @param numeric $gender
     */
    public function getByAgeRangeAndGender($minAge, $maxAge , $gender)
    {
        $minAge = (int) $minAge;
        $maxAge = (int) $maxAge;
        $gender = (int) $gender;
        $result = $this-&gt;find(
            'all',
            array(
                'conditions' =&gt; array(
                    'gender' =&gt; $gender,
                    'age &lt;' =&gt; $maxAge,
                    'age &gt;' =&gt; $minAge,
                )
            )
        );
        return $result;
    }
}
</pre>
<p>若干気持ち悪いが連想配列なのでまぁしょうがない。</p>
<h5>OR</h5>
<p>conditionsに追加すると全てANDで結合した条件となる。ORにする場合は以下のように記述する。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * getByAgeRangeAndGender
     * 年齢の範囲と性別でユーザを検索する
     * @param numeric $minAge
     * @param numeric $maxAge
     * @param numeric $gender
     */
    public function getByAgeAndGender($minAge, $maxAge , $gender)
    {
        $minAge = (int) $minAge;
        $maxAge = (int) $maxAge;
        $gender = (int) $gender;
        $result = $this-&gt;find(
            'all',
            array(
                'conditions' =&gt; array(
                    'gender' =&gt; $gender,
                    'or' =&gt; array(
                        'age &gt;' =&gt; $maxAge,
                        'age &lt;' =&gt; $minAge,
                    )
                )
            )
        );
        return $result;
    }
}
</pre>
<h5>NOT</h5>
<p>NOTにする場合は以下のように記述する。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * getTarget
     * 血液型が入力されているユーザをサービスのターゲットとして検索する
     * @param string $type
     */
    public function getTarget($type)
    {
        $result = $this-&gt;find(
            'all',
            array(
                'conditions' =&gt; array(
                    'not' =&gt; array(
                        'blood_type' =&gt; null
                    )
                )
            )
        );
        return $result;
    }
}
</pre>
<h5>順序</h5>
<p>以下のようにすることでORDER BYと同じになる。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * getByAgeAndGender
     * 年齢と性別でユーザを検索する
     * @param numeric $age
     * @param numeric $gender
     */
    public function getByAgeAndGender($age , $gender)
    {
        $age    = (int) $age;
        $gender = (int) $gender;
        $result = $this-&gt;find(
            'all',
            array(
                'conditions' =&gt; array(
                    'age'    =&gt; $age,
                    'gender' =&gt; $gender,
                ),
                'order' =&gt; array(
                    'age desc',
                    'gender asc',
                )
            )
        );
        return $result;
    }
}
</pre>
<h5>結合</h5>
<p>例えば職業テーブルが存在しユーザが職業IDを持つ場合に結合する必要もあるはずだ。以下のようにして結合する。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * getByOccupation
     * @param string $occupation
     */
    public function getByOccupation($occupation)
    {
        $alias = 'Occupation';
        $result = $this-&gt;find(
            'all',
            array(
                'fields' =&gt; array(
                    &quot;`{$this-&gt;name}`.`id`&quot;,
                    &quot;`{$this-&gt;name}`.`name`&quot;,
                    &quot;`{$alias}`.`name`&quot;,
                ),
                'conditions' =&gt; array(
                    &quot;`{$this-&gt;name}`.`gender`&quot; =&gt; $gender,
                ),
                'joins' =&gt; array(
                    array(
                        'type'       =&gt; 'LEFT',
                        'table'      =&gt; 'occupations',
                        'alias'      =&gt; $alias,
                        'conditions' =&gt; &quot;`{$this-&gt;name}`.`occupations_id` = `{$alias}`.`id`&quot;,
                    )
                ),
            )
        );
        return $result;
    }
}
</pre>
<p>fieldsを使用しない場合は結合したテーブルのカラムが取り出せない。結合しないクエリにおいて、fieldsを使用しない場合に発行されるクエリは以下のとおりとなる。</p>
<pre class="brush: sql;">
SELECT * FROM `user` WHERE `id` = ?;
</pre>
<p>fieldsを使用しないとアスタリスクとなり全てのカラムがfetchされるので注意が必要だ。</p>
</section>
<h3>■保存</h3>
<p>CakePHPでは明確にInsertとUpdateが分離されていない。プライマリキーがセットされている場合はUpdateの扱いとなる。</p>
<h4>Insert</h4>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * register
     * 登録してIDを返す
     * @param string $name
     * @param numeric $age
     */
    public function register($name, $age)
    {
        $age    = (int) $age;
        $result = $this-&gt;save(
            array(
                'name' =&gt; $name,
                'age'  =&gt; $age,
            )
        );
        return ($result)? $this-&gt;getLastInsertID() : $result;
    }
}
</pre>
<h4>Update</h4>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * register
     * 登録してIDを返す
     * @param string $name
     * @param numeric $age
     * @param numeric $id
     */
    public function register($name, $age, $id)
    {
        $id    = (int) $id;
        $result = $this-&gt;save(
            array(
                'id'   =&gt; $id,
                'name' =&gt; $name,
                'age'  =&gt; $age,
            )
        );
        return $result;
    }
}
</pre>
<h3>■削除</h3>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * del
     * @param numeric $id
     */
    public function del($id)
    {
        $this-&gt;delete((int) $id);
    }
}
</pre>
<p>第二引数でcascadeも指定できるけど、MySQLで直接定義してるよね・・・。以下のように条件で削除することもできる。</p>
<pre class="brush: php;">
class User extends AppModel {
    public $name = 'User';
    // validationは省略

    /**
     * del
     * @param string $name
     */
    public function del($name)
    {
        $this-&gt;deleteAll(array(
            'name' =&gt; $name
        ));
    }
}
</pre>
<p>大体モデルはコンナ感じでいいかな。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/07/20/cakephp%e3%81%a7%e3%83%a2%e3%83%87%e3%83%ab%e3%82%92%e4%bd%9c%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPを使う準備をする</title>
		<link>http://blog.justoneplanet.info/2011/07/13/cakephp%e3%82%92%e4%bd%bf%e3%81%86%e6%ba%96%e5%82%99%e3%82%92%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/07/13/cakephp%e3%82%92%e4%bd%bf%e3%81%86%e6%ba%96%e5%82%99%e3%82%92%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 15:51:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4177</guid>
		<description><![CDATA[今更な感があるがメモとして残しておく。さらに面倒なのでローカルのXAMPPで説明する。 ■ダウンロード 以下のようにダウンロードして解凍する。 mkdir cake.sample.justoneplanet.info c [...]]]></description>
			<content:encoded><![CDATA[<p>今更な感があるがメモとして残しておく。さらに面倒なのでローカルのXAMPPで説明する。</p>
<h3>■ダウンロード</h3>
<p>以下のようにダウンロードして解凍する。</p>
<pre class="brush: bash;">
mkdir cake.sample.justoneplanet.info
cd cake.sample.justoneplanet.info/
wget https://github.com/cakephp/cakephp/tarball/1.3.10
tar xvzf cakephp-cakephp-1.3.10-0-g8671aa3.tar.gz
rm cakephp-cakephp-1.3.10-0-g8671aa3.tar.gz
rm -fr cakephp-cakephp-b0abad1/
</pre>
<p>以下のような状態になっている。</p>
<ul>
<li>cake.sample.justoneplanet.info/app</li>
<li>cake.sample.justoneplanet.info/cake</li>
<li>cake.sample.justoneplanet.info/plugins</li>
<li>cake.sample.justoneplanet.info/vendors</li>
<li>cake.sample.justoneplanet.info/index.php</li>
<li>cake.sample.justoneplanet.info/README</li>
</ul>
<h3>■Apacheの設定</h3>
<p>まぁ、バーチャルホストの設定を変更する。</p>
<pre class="brush: php;">
vi /Applications/XAMPP/etc/extra/httpd-vhosts.conf
</pre>
<pre class="brush: xml;">
&lt;VirtualHost *:80&gt;
    DocumentRoot &quot;/Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app/webroot&quot;
    ServerName cake.sample.justoneplanet.info
    ServerAlias www.cake.sample.justoneplanet.info
#    SetEnv CAKE_ENV default
&lt;/VirtualHost&gt;
</pre>
<p>hostsファイルを変更しApacheを再起動する。</p>
<h3>■パーミッションの設定</h3>
<p>起動すると大量のエラー文が表示されるので、以下のコマンドを実行してパーミッションを変更する。</p>
<pre class="brush: bash;">
chmod -R 0777 app/tmp/
</pre>
<p>また、以下のコマンドを実行して「Security.salt」と「Security.cipherSeed」を変更する。</p>
<pre class="brush: bash;">
vi app/config/core.php
</pre>
<h3>■データベースの設定</h3>
<p>ファイルを直接編集しても良いんだけど、せっかくなのでbakeを使う。</p>
<pre class="brush: bash;">
./cake/console/cake bake
</pre>
<p>以下のように表示されるので順に設定する。</p>
<pre class="brush: bash;">
Welcome to CakePHP v1.3.10 Console
---------------------------------------------------------------
App : app
Path: /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app
---------------------------------------------------------------
Your database configuration was not found. Take a moment to create one.
---------------------------------------------------------------
Database Configuration:
---------------------------------------------------------------
Name:
[default] &gt; default
Driver: (db2/firebird/mssql/mysql/mysqli/odbc/oracle/postgres/sqlite/sybase)
[mysql] &gt; mysql
Persistent Connection? (y/n)
[n] &gt; n
Database Host:
[localhost] &gt; localhost
Port?
[n] &gt; n
User:
[root] &gt; hogehoge
Password:
&gt; **********
Database Name:
[cake] &gt; sample
Table Prefix?
[n] &gt; n
Table encoding?
[n] &gt; utf8
</pre>
<p>設定が終わると確認メッセージが表示され他のデータベース設定をするか聞かれる。</p>
<pre class="brush: bash;">
Look okay? (y/n)
[y] &gt; y
Do you wish to add another database configuration?
[n] &gt; y
</pre>
<p>今回は以下のようにしてもう一つ設定する。</p>
<pre class="brush: bash;">
Welcome to CakePHP v1.3.10 Console
---------------------------------------------------------------
App : app
Path: /Applications/XAMPP/xamppfiles/htdocs/cake.sample.justoneplanet.info/app
---------------------------------------------------------------
Your database configuration was not found. Take a moment to create one.
---------------------------------------------------------------
Database Configuration:
---------------------------------------------------------------
Name:
[default] &gt; production
Driver: (db2/firebird/mssql/mysql/mysqli/odbc/oracle/postgres/sqlite/sybase)
[mysql] &gt; mysql
Persistent Connection? (y/n)
[n] &gt; n
Database Host:
[localhost] &gt; localhost
Port?
[n] &gt; n
User:
[root] &gt; hogehoge
Password:
&gt; **********
Database Name:
[cake] &gt; sample
Table Prefix?
[n] &gt; n
Table encoding?
[n] &gt; utf8
</pre>
<p>開発用と本番用で設定を用意した。開発上は関係ないと思われるが、以前に使用していたdevelopmentという名前だと配置した段階でdefaultという設定名が必要になるようなので、開発環境はdefaultという名前を用いることにした。</p>
<h4>app/app_model.php</h4>
<p>以下のように記述して本番環境用の設定も読み込めるようにする。</p>
<pre class="brush: php;">
class AppModel extends Model {
    /**
     * __construct
     * @param mixed $id
     * @param mixed $table
     * @param mixed $ds
     */
    public function __construct($id = false, $table = null, $ds = null)
    {
        $this-&gt;useDbConfig = Configure::read('Config.environment');
        parent::__construct($id, $table, $ds);
    }
}
</pre>
<h3>■開発環境と本番環境の設定の分離</h3>
<p>以下のコマンドを実行する。</p>
<pre class="brush: bash;">
vi app/config/bootstrap.php
mkdir app/config/environment
</pre>
<p>以下の記述を最終行に付加する。</p>
<pre class="brush: php;">
Configure::write('Config.environment', isset($_SERVER['CAKE_ENV']) ? $_SERVER['CAKE_ENV'] : &quot;default&quot;);
require_once(&quot;environment/&quot; . basename(Configure::read('Config.environment') . &quot;.php&quot;));
</pre>
<p>新しくできたディレクトリに以下の2ファイルを追加する。</p>
<h4>default.php</h4>
<p>開発用設定ファイル。</p>
<pre class="brush: php;">
Configure::write('debug', 2);
Configure::write('Cache.disable', true);
</pre>
<p>エラーメッセージを表示するのと、キャッシュを無効にしておく。</p>
<h4>production.php</h4>
<p>本番用設定ファイル。</p>
<pre class="brush: php;">
Configure::write('debug', 0);
Configure::write('Cache.disable', false);
</pre>
<p>エラーメッセージは見せないようにする。</p>
<h3>■おまけ</h3>
<p>PHP5.3以上を使っていると思うので、core.php以下の部分をコメントアウトし引数を変更する。</p>
<pre class="brush: php;">
date_default_timezone_set('Asia/Tokyo');
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/07/13/cakephp%e3%82%92%e4%bd%bf%e3%81%86%e6%ba%96%e5%82%99%e3%82%92%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPでCSVのダウンロードをする</title>
		<link>http://blog.justoneplanet.info/2011/05/25/cakephp%e3%81%a7csv%e3%81%ae%e3%83%80%e3%82%a6%e3%83%b3%e3%83%ad%e3%83%bc%e3%83%89%e3%82%92%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/05/25/cakephp%e3%81%a7csv%e3%81%ae%e3%83%80%e3%82%a6%e3%83%b3%e3%83%ad%e3%83%bc%e3%83%89%e3%82%92%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Wed, 25 May 2011 04:41:06 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4225</guid>
		<description><![CDATA[ベタに書いてもいいんだけどアレなんでヘルパーを使う。 ■ヘルパー vi app/views/helpers/csv.php CSV Helper (PHP 5)のコードをペーストする。 コントローラ App::impor [...]]]></description>
			<content:encoded><![CDATA[<p>ベタに書いてもいいんだけどアレなんでヘルパーを使う。</p>
<h3>■ヘルパー</h3>
<pre class="brush: bash;">
vi app/views/helpers/csv.php
</pre>
<p><a href="http://bakery.cakephp.org/articles/ifunk/2007/09/10/csv-helper-php5">CSV Helper (PHP 5)</a>のコードをペーストする。</p>
<h4>コントローラ</h4>
<pre class="brush: php;">
App::import('Helper', 'Csv');
</pre>
<pre class="brush: php;">
var $helpers = array(
    'Csv'
);
</pre>
<h3>■データ挿入</h3>
<pre class="brush: php;">
Configure::write('debug', 0);
$this-&gt;layout = false;
$line = array('hogehoge', 'fugafuga', 'piyopiyo');
$csv-&gt;addRow($line);
</pre>
<h3>■出力</h3>
<pre class="brush: php;">
echo $csv-&gt;render('data.csv', 'sjis', 'utf-8');
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/05/25/cakephp%e3%81%a7csv%e3%81%ae%e3%83%80%e3%82%a6%e3%83%b3%e3%83%ad%e3%83%bc%e3%83%89%e3%82%92%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPのページャーにクエリを付加する</title>
		<link>http://blog.justoneplanet.info/2011/05/11/cakephp%e3%81%ae%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%a3%e3%83%bc%e3%81%ab%e3%82%af%e3%82%a8%e3%83%aa%e3%82%92%e4%bb%98%e5%8a%a0%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/05/11/cakephp%e3%81%ae%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%a3%e3%83%bc%e3%81%ab%e3%82%af%e3%82%a8%e3%83%aa%e3%82%92%e4%bb%98%e5%8a%a0%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Tue, 10 May 2011 16:48:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4175</guid>
		<description><![CDATA[以下のようにoptionsに記述する。 $this-&#62;paginate = array( 'page' =&#62; 1,// 初期選択ページ 'limit' =&#62; 100,// 1ページあたりの件数 'ord [...]]]></description>
			<content:encoded><![CDATA[<p>以下のようにoptionsに記述する。</p>
<pre class="brush: php;">
$this-&gt;paginate = array(
    'page'   =&gt; 1,// 初期選択ページ
    'limit'  =&gt; 100,// 1ページあたりの件数
    'order'  =&gt; array('created' =&gt; 'desc'),// 順序
    'fields' =&gt; 'id, name, birthday, created',
    'joins'  =&gt; array(
        array(
            'type'       =&gt; 'LEFT',
            'alias'      =&gt; 'Data',
            'table'      =&gt; 'datas',
            'conditions' =&gt; &quot;User.id = Data.users_id&quot;
        ),
    ),
    'options'  =&gt; array(
        '?' =&gt; array(
            'param' =&gt; 'hogehoge'
        )
    )
);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/05/11/cakephp%e3%81%ae%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%a3%e3%83%bc%e3%81%ab%e3%82%af%e3%82%a8%e3%83%aa%e3%82%92%e4%bb%98%e5%8a%a0%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPでデータを保存する</title>
		<link>http://blog.justoneplanet.info/2011/05/08/cakephp%e3%81%a7%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e4%bf%9d%e5%ad%98%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.justoneplanet.info/2011/05/08/cakephp%e3%81%a7%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e4%bf%9d%e5%ad%98%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Sun, 08 May 2011 14:23:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4277</guid>
		<description><![CDATA[CakePHPでデータをDBに保存するときは新規登録でも更新でもsaveメソッドを使用する。 ■新規登録 新規登録の際は以下のようにcreateメソッドを用いる。 $this-&#62;User-&#62;create(); [...]]]></description>
			<content:encoded><![CDATA[<p>CakePHPでデータをDBに保存するときは新規登録でも更新でもsaveメソッドを使用する。</p>
<h3>■新規登録</h3>
<p>新規登録の際は以下のようにcreateメソッドを用いる。</p>
<pre class="brush: php;">
$this-&gt;User-&gt;create();
$this-&gt;User-&gt;save($this-&gt;data, true, array('name', 'password'));
</pre>
<h3>■更新</h3>
<p>更新する際は以下のようにidに更新するレコードの値をセットする。</p>
<pre class="brush: php;">
$this-&gt;User-&gt;id = 32;
$this-&gt;User-&gt;save($this-&gt;data, true, array('name', 'password'));
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/05/08/cakephp%e3%81%a7%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e4%bf%9d%e5%ad%98%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHPとMySQLのON UPDATE CURRENT_TIMESTAMPを使う</title>
		<link>http://blog.justoneplanet.info/2011/05/08/cakephp%e3%81%a8mysql%e3%81%aeon-update-current_timestamp%e3%82%92%e4%bd%bf%e3%81%86/</link>
		<comments>http://blog.justoneplanet.info/2011/05/08/cakephp%e3%81%a8mysql%e3%81%aeon-update-current_timestamp%e3%82%92%e4%bd%bf%e3%81%86/#comments</comments>
		<pubDate>Sun, 08 May 2011 14:07:02 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=4275</guid>
		<description><![CDATA[CakePHPにおいてON UPDATE CURRENT_TIMESTAMPを使用すると、文字列としてCURRENT_TIMESTAMPを格納しようとするので、MySQL側でTIMESTAMPとして処理できない。以下のよ [...]]]></description>
			<content:encoded><![CDATA[<p>CakePHPにおいてON UPDATE CURRENT_TIMESTAMPを使用すると、文字列としてCURRENT_TIMESTAMPを格納しようとするので、MySQL側でTIMESTAMPとして処理できない。以下のようにすることで対処できる。</p>
<h3>■CURRENT_TIMESTAMP</h3>
<p>modifiedというカラム名をつければCakeが自動的に更新日時をセットするので必ずしもON UPDATE CURRENT_TIMESTAMPをセットする必要はない。</p>
<h3>■saveメソッド</h3>
<p>習慣とは恐ろしい物で付けたい物は付けたいのだ。saveメソッドで保存するカラムを指定することで対処できる。</p>
<pre class="brush: php;">
$this-&gt;User-&gt;save($this-&gt;data, true, array('name', 'birthday'));
</pre>
<p>上述のようにすることで$this->dataにあらゆるキーとそれに紐付く値が格納されていても、保存されるのはnameカラムとbirthdayカラムのみである。これはアプリケーションをセキュアにする目的でも使用できるので、常時使用することをお勧めする。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2011/05/08/cakephp%e3%81%a8mysql%e3%81%aeon-update-current_timestamp%e3%82%92%e4%bd%bf%e3%81%86/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

