CakePHPでJavaScriptを使う

以前の記事(CakePHPでjQueryのDatePickerを使う - yokkongの日記)で、こんなコードを書いていた。

<?php
$this->Html->scriptStart(array('inline' => false));
echo <<< END
function test(){
    alert("クリックしました");
}
END;
$this->Html->scriptEnd();
?>

これはこれで間違ってはいないのだけれど、JavaScriptの中でCakePHPの値を使うときにどう書いていいのか分からなかった。
そこで、

<?php $this->Html->scriptStart(array('inline' => false)); ?>
function test(){
    alert("クリックしました");
}
<?php $this->Html->scriptEnd(); ?>

とすることで、JavaScriptの中でCakePHPの値を使えるようにした。

<?php $this->Html->scriptStart(array('inline' => false)); ?>
$(function() {
  $( "#search" )
    .button()
    .click(function() {
      $.ajax({
        url:'<?php echo $this->Html->url('/users/search'); ?>',
        ...(以下略)
      });
    });
});
<?php $this->Html->scriptEnd(); ?>

こんな感じ。

CakePHPでSearchプラグインを使ってみた

CakePHPで検索機能を作るにはどうすればいいのかな?と思いGoogle検索してみると、Searchプラグインなるものを発見。
さっそく試してみた。
参考にしたサイト
Searchプラグインを使ってCakePHPに検索を実装する | mawatari.jp
その他、「CakePHP Search Plugin」でググってヒットするいろいろなサイトを参考にさせていただきました。

Searchプラグインの導入

まず、GitHubからCakeDC/Searchをダウンロードする。
https://github.com/CakeDC/search
ダウンロードしたsearch-master.zipを解凍し、search-masterフォルダをSearchにリネームしてapp/Pluginにコピーする。
app/core/bootstrap.phpに以下を追加する。

CakePlugin::load('Search');

これでSearchプラグインが使えるようになった。

Searchプラグインを使う

Searchプラグインの使用例は上記サイトをはじめいろいろなところで紹介されているのでそちらを見た方が分かりやすい。
ここでは検索条件にラジオボタンを使った場合について書いておくことにする。
例えばusersテーブルにgender(varchar(1))というフィールドがあって、m=男性、w=女性だとする。
検索条件として『○すべて ○男性 ○女性』みたいなラジオボタンのグループを作り、『男性/女性』が選択された場合はその条件で検索、『すべて』が選択された場合は検索条件に含めない、というようなことをやりたい。
検索画面のHTMLはこんな感じ

<input type="radio" name="data[User][gender]" id="UsergenderNone" class="rental" value="none" />すべて
<input type="radio" name="data[User][gender]" id="UsergenderW" class="rental" value="w" />女性
<input type="radio" name="data[User][gender]" id="UsergenderM" class="rental" value="m" />男性

モデル

<?php
class User extends AppModel{
    // ビヘイビアの定義
    public $actsAs = array('Search.Searchable');

    // 検索フィルタの定義
    public $filterArgs = array(
        // 独自のフィルタを定義
        'gender' => array('type' => 'query', 'method' => 'searchGender'),
    );

    // 検索用フィルタ
    function searchGender($data = array()){
        $filter = $data['gender'];
        // 「すべて」選択時は条件無し
        if (($filter=='m') || ($filter=='w')){
            $conditions = array('gender' => $filter);
        } else {
            $conditions = array();
        }
        return $conditions;
        }
    }
?>

まず、モデルでSearchビヘイビアを使用するためにactAsを定義する。
次に実際の検索条件を設定するためにfilterArgsを定義する。
検索パターンにはいろいろなものが用意されていて、例えば『'type' => 'value'』なら完全一致、『'type' => 'like'』なら部分一致という具合。
その中で『'type' => 'query'』とすると、『'method' => 'メソッド名'』で定義したメソッドを使用して独自の検索条件を定義できる。
今回の場合、「m:男性/w:女性」が選択された場合はその条件を定義して返し、それ以外の場合は空の配列を返すようにした。
実際には『array('m' => '男性', 'w' => '女性')』みたいなのをapp/Configに定義してbootstrap.phpで『Configure::load('xxx')』としておき、その配列に存在するか?みたいな判定方法がいいのかもしれない。
とりあえずこのqueryを使うとたいていの検索処理は実装できそう。

CakePHPでDatepickerの続き

CakePHPでjQueryのDatePickerを使う - yokkongの日記
先日の記事の続き。

とりあえずDatepickerヘルパーを作成して日付のカレンダー表示ができるようになったわけだけれども、一つのHTMLで複数のDatepickerヘルパーを使用した場合(例えば検索画面で日付の範囲指定など)、次のようなコードが出力されていた。

<link rel="stylesheet" type="text/css" href="/wendy/css/jquery-ui-1.10.3.custom.css" />
<link rel="stylesheet" type="text/css" href="/wendy/css/jquery-ui-1.10.3.custom.css" />
<script type="text/javascript" src="/wendy/js/jquery-1.9.1.js"></script>
<script type="text/javascript" src="/wendy/js/jquery-ui-1.10.3.custom.js"></script>
<script type="text/javascript" src="/wendy/js/jquery.ui.datepicker-ja.js"></script>
<script type="text/javascript">
//<![CDATA[
jQuery(function($){$("#fromdate").datepicker({changeMonth: true,changeYear: true, yearRange:"1900:2023"});});
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
jQuery(function($){$("#todate").datepicker({changeMonth: true,changeYear: true, yearRange:"1900:2023"});});
//]]>
</script>

なぜかJavascriptは一つしか出ていないのにCSSは重複してしまう。
これでも問題無いのだろうが、とりあえずjQueryの読み込みはヘルパーでなくビュー側で行うようにした。

個別のビューに書くかレイアウトに書くかは使用頻度に寄るのかな?

個別のビューに書く場合は、

$this->Html->script('jquery-1.9.1', array('inline' => false));
$this->Html->script('jquery-ui-1.10.3.custom', array('inline' => false));
$this->Html->script('jquery.ui.datepicker-ja', array('inline' => false));
$this->Html->css('jquery-ui-1.10.3.custom', null, array('inline' => false));

レイアウトに書く場合は内に

echo $this->Html->script('jquery-1.9.1');
echo $this->Html->script('jquery-ui-1.10.3.custom');
echo $this->Html->script('jquery.ui.datepicker-ja');
echo $this->Html->css('jquery-ui-1.10.3.custom');

注意点としては、内の『echo $this->fetch('script');』よりも前に書くこと。

あとはdatepickerを参照している部分、例えば上記の場合だと

<script type="text/javascript">
//<![CDATA[
jQuery(function($){$("#fromdate").datepicker({changeMonth: true,changeYear: true, yearRange:"1900:2023"});});
//]]>
</script>
<script type="text/javascript">
//<![CDATA[
jQuery(function($){$("#todate").datepicker({changeMonth: true,changeYear: true, yearRange:"1900:2023"});});
//]]>
</script>

この部分も

<script type="text/javascript">
//<![CDATA[
jQuery(function($){$("#fromdate, #todate").datepicker({changeMonth: true,changeYear: true, yearRange:"1900:2023"});});
//]]>
</script>

と書くこともできるのだが、それをCakePHPで実装できるのかどうかは分からないのでとりあえずはこのまま。

CakePHPでjQueryのDatePickerを使う

CakePHPでDATE型のフィールドをViewに表示するとき、

echo $this->Form->input('birthday');

と書くと年、月、日それぞれがSELECTタグとして出力される。

最近jQueryを使い始めて、jQuery UIの中にDatePickerというカレンダー形式で日付を入力できるものがあると知ったので、それを使えないか色々試してみた。

CakePHPJavaScriptを使う

まずはJavaScriptCakePHPで使う方法について。
Viewの中で$this->Html->scriptStart()と$this->Html->scriptEnd()の間にJavaScriptのコードを書く。

$this->Html->scriptStart(array('inline' => false));
echo <<< END
function test(){
    alert("クリックしました");
}
END;
$this->Html->scriptEnd();
echo $this->Form->button('押してください', array('type' => 'button', 'onClick'=>'test();'));

scriptStart()の引数に何も指定しないと記述した場所にコードが生成されるが、『array('inline' => false)』を指定するとヘッダーの中にコードが生成される。
ちなみに外部のファイルを読み込む場合は、

$this->Html->script('test', array('inline' => false));

と記述する。

CakePHPjQueryを使う

のちほどDatePickerを使うので、jQuery UIのサイトからファイルをダウンロードする。
http://jqueryui.com/
Downloadページに行くと必要なライブラリやデザインを選べるようになっている。
とりあえず今回はライブラリは全部、デザインは『No Theme』にした。
ダウンロードしたjquery-ui-1.10.3.custom.zipを解凍し、

をwebroot\jsに、

をwebroot/cssにコピーする。
Viewは以下のようになる。

$this->Html->script('jquery-1.9.1', array('inline' => false));
$this->Html->script('jquery-ui-1.10.3.custom', array('inline' => false));
$this->Html->css('jquery-ui-1.10.3.custom', null, array('inline' => false));
$this->Html->scriptStart(array('inline' => false));
echo <<< END
$(document).ready( function() {
    $("button#button1").click(function(){
        alert('クリックしました');
    });
});
END;
$this->Html->scriptEnd();
echo $this->Form->button('押してください', array('type' => 'button', 'id'=>'button1'));

jQueryの読み込みについてはとりあえず個別のViewの中に書いてみたが、jQueryを使う画面が多くなってきた場合を考えると、レイアウトの中に書いたほうがいいのかもしれない。

CakePHPjQuery UIのDatePickerを使う

DatePickerを使う前に日本語対応する。
解凍したjQuery UIフォルダの中に『development-bundle\ui\i18n\jquery.ui.datepicker-ja.js』というファイルがあるのでこれをwebroot\jsにコピーする。

$this->Html->script('jquery-1.9.1', array('inline' => false));
$this->Html->script('jquery-ui-1.10.3.custom', array('inline' => false));
$this->Html->script('jquery.ui.datepicker-ja', array('inline' => false));
$this->Html->css('jquery-ui-1.10.3.custom', null, array('inline' => false));
$this->Html->scriptStart(array('inline' => false));
echo <<< END
$(document).ready( function() {
    $( "#datepicker" ).datepicker();
});
END;
$this->Html->scriptEnd();
echo "<div>Birthday: <input type='text' id='datepicker' /></div>";

これでテキストボックスをクリックすると日付選択のカレンダーが表示されるようになった。

CakePHPjQuery UIのDatePickerを使うヘルパーを作成してみる

DatePickerの使い方が分かったので、Viewで使いやすいようにヘルパーを作ってみる。
こちらのサイトを参考にさせていただきました。
jqueryのdataPickerを使って日付をカレンダーから入力する - わんコロ餅。
ただし、こちらで書かれているのはCakePHP1.2のコードなので、2.Xに合わせていろいろ修正。

app\View\Helper\DatePickerHelper.php

<?php
    class DatepickerHelper extends AppHelper{
    //ヘルパー
    var $helpers = array("Form","Html");

    function datepicker($fieldName, $options = array()){
        //外部ファイル
        $ext = $this->Html->script('jquery-1.9.1', array('inline' => false))
            . $this->Html->script('jquery-ui-1.10.3.custom', array('inline' => false))
            . $this->Html->script('jquery.ui.datepicker-ja', array('inline' => false))
            . $this->Html->css('jquery-ui-1.10.3.custom', null, array('inline' => false));

        //テキストボックスのhtml
        $ext .= $this->Form->input($fieldName, $options);

        //テキストボックスのID
        if(isset($options["id"])) {
            $id = $options["id"];
        } else {
            $id = $this->Form->domId(array(), "for");
        }
        //スクリプト部分
        $script =
            "jQuery(function($){".
            "$(\"#".$id["for"]."\").datepicker({changeMonth: true,changeYear: true});".
            "});";

        return $ext . $this->Html->scriptBlock($script, array('inline' => false)); }
    }
?>

DatePickerのオプションについてはこちらのサイトを参考にさせていただきました。
Datepicker | jQuery UI 1.10 日本語リファレンス | js STUDIO
例えば、datepicker({changeMonth: true,changeYear: true})とすればカレンダーの上部に年、月を選択する領域が表示される。

ビューでヘルパーを使うために、コントローラーの$helpersにヘルパーの名前を書く。

var $helpers = array("DatePicker");

ビューでの書き方は次のようになる。

echo $this->Datepicker->datepicker('Birthday');

CakePHPでDATE型のフィールドをDatePicker対応のテキストに表示する

id(INT)、name(VARCHAR)、birthday(DATE)を持つテーブルUsersがあったとして、これを表示しようとすると、

echo $this->Form->create('User');
echo $this->Form->input('name');
echo $this->Form->input('birthday');
echo $this->Form->input('id', array('type' => 'hidden')); 
echo $this->Form->end('更新');

という感じのビューになる(はず)。

このままだとbirthdayは年、月、日のSELECTで表示されるので、ここをDatePickerヘルパーに置き換えてみる。

echo $this->Form->create('User');
echo $this->Form->input('name');
echo $this->Datepicker->datepicker('birthday', array('type' => 'text'));
echo $this->Form->input('id', array('type' => 'hidden')); 
echo $this->Form->end('更新');

『array('type' => 'text')』がポイントで、これが無いとテキストボックスを表示してくれない。
もっとも一つのシステム内で日付の入力形式がバラバラなのも問題なので、ヘルパー側で

$options = array_merge(array('type' => 'text'), $options);

としたほうがいいのかもしれない。
まだ日付チェックなどが残っているが、とりあえずカレンダー形式で日付を入力できるようになった。

CakePHP+NetBeans+xdebugでデバッグ

NetBeansxdebug使うとPHPデバッグが捗る」と聞いたのでインストールしてみた。
これまでVB開発、Android開発をやってきた自分としては、Visual StudioEclipseと同じようなデバッグができて大変便利。

しかし、CakePHPで作ったアプリをデバッグしようと思い、NetBeansからデバッグ実行してみると何故かブレークポイントを設定した位置で止まってくれない。それだけでなくコメント行で止まっていたりする。ただのPHPだと何も問題無かったのに・・・と思いいろいろ調べてみると、実行構成の開始ファイルは「index.php」ではなく「app/webroot/index.php」にしないといけないらしい。
というわけで実行構成を変更してデバッグ実行したところ、きちんとブレークポイントを設定した場所で止まってくれた。

参考:
http://www.ryuzee.com/contents/blog/3522

CakePHPのリクエストデータの編集

リクエストデータの値を編集しようとしたとき、1だと

$this->data['Hoge']['Moge'] = '何かの値';

としていたけれど、2では

$this->request->data['Hoge']['Moge'] = '何かの値';

こうなる。$this->dataはreadonlyらしい。
参考:http://pugiemonn.blog6.fc2.com/blog-entry-1372.html

CakePHPメモ

CakePHP勉強中

仕事でCakePHPを使うことになったのでいろいろ勉強中。
自分で使うのは初めてなので、過去に会社の人が作ったソースを参考に・・・
と思ったらそのソース、CakePHPのバージョンが1.2で2.xとはだいぶ作りが違う。
おまけにPHPのバージョンも違うのでそのまま動かそうとするとうまくいかないケースが多い。
というわけで、初めてCakePHPを使うに当たりいろいろと気付いた点、はまった点などをメモしていく予定。

CakePHPの概要を押さえるには公式のチュートリアルが一番分かりやすいと思う。
http://book.cakephp.org/2.0/ja/tutorials-and-examples/blog/blog.html
あともう1つ参考にしたサイト
初心者のためのCakePHP2 プログラミング入門 - libro

ネットにはCakePHPに関する情報はたくさんあるのだけれど、バージョン1.xをベースに書かれていることも多く、
そのまま自分の環境で試そうとするとうまくいかないこともしばしば。
なので、2.xからCakePHPを使う人も移行ガイドに目を通しておくといろいろ役に立つのかもしれない。
http://book.cakephp.org/2.0/ja/appendices/2-0-migration-guide.html

使用環境について

自分の環境は以下の通り。

Windows 7 Professional SP1
CakePHP 2.3.5
XAMPP 1.8.1
Apache 2.4.3
PHP 5.4.7
MySQL 5.5.27

参考サイト
http://cakephp.jp/
http://www.apachefriends.org/jp/xampp.html