Posts Tagged ‘cakephp’

    はてなブックマーク - PHPmatsriにてCsvCombinePluginを紹介してきました。
    このエントリーをはてなブックマークに追加

    ブログはお久しぶりです。萩原です。

    今回は、PHPmatsuriに弊社、小山、櫻川、杉本と、私の4人で行ってきました。

    PHPmatsuriの感想

    私は、ハッカソンという形式のイベントは初めてで、LTも初めてでしたので非常に緊張しましたが、何とか無事に発表まで終える事が出来て良かったです。

    発表でおーと声が上がった時は非常にうれしかったです。
    後、下記にも載せているホークスのスタメンを出したときに、「何でそんなマニアックな」と言って下さった方、ありがとうございます。
    あれが一番うれしかったりします(笑)。

    普段、私はCakePHPを扱っていますが、SymfonyやLithiumなどの他のフレームワークについてはまったくといっていいほど知りませんでしたので、その二つのセッションを両フレームワークの開発者から聞けたことも非常に貴重な機会でした。

    また、開発風景やLTの発表を見まして、皆さんすごい、もっと自分も頑張らないとと改めて感じました。

    CsvCombinePlugin

    さて、今回私がPHPmatsuriで紹介しました、CsvCombinePluginについてご紹介したいと思います。

    このプラグインはCSVの入出力の処理を簡単に行うことが出来るプラグインです。
    CakePHP1.3と2.0の両方のブランチをGithubで用意しています。

    せっかくですのでCakePHP2の方式で紹介したいと思います。

    まずはこちらのGithubの”cake2″というブランチよりダウンロードしてきて、Pluginディレクトリ内に”CsvCombine”とrenameして下さい。

    CSVの入力

    まずはCSVを添付して配列で返すメソッドを紹介します。

    モデルにBehaviorを宣言します。

    <?php
    App::uses(&#039;AppModel&#039;,&#039;Model&#039;);
    CakePlugin::load(&#039;CsvCombine&#039;);
    class CsvTest extends AppModel{
        var $actsAs = array(&#039;CsvCombine.CsvImport&#039;);
    }

    後は、コントローラで列ごとの配列のキー値を指定したらアクションをたたいて完了です。

    <?php
    App::uses(&#039;AppController&#039;,&#039;Controller&#039;);
        class CsvTestsController extends AppController{
        var $name = &#039;CsvTests&#039;;
    
        function index(){
            if ($this->request->is(&#039;post&#039;)) {
               /***基本必要な個所***/
               //配列のキー値を左から指定
                $list = array(&#039;打順&#039;, &#039;守備&#039;,&#039;名前&#039;,&#039;打率&#039;,&#039;HR&#039;,&#039;打点&#039;);
                //このアクションで配列が返ってくる
                $data = $this->CsvTest->csvData($list);
                 /***!基本必要な個所***/
                if ($data === false) {
                    print_r(&#039;MISS&#039;);
                    exit;
                }
                print_r($data);
                exit;
            }
     
        }

    これで下記の様なCSVを添付すると・・・(PHPmatsuri1日目夜の日のホークスのスタメンです・・・)

    1,遊,川﨑,.271,1,37
    2,二,本多,303,0,43
    3,左,内川,.341,12,73
    4,三,松田,.283,25,83
    5,中,長谷川,.293,4,34
    6,右,福田,.256,1,20
    7,DH,柴原,.077,0,0
    8,一,明石,.277,1,12
    9,捕,山崎,.191,0,11
    P,投,杉内,.200,0,3
    

    以下のような配列が返ってきます。(preで整形しています。

    Array
    (
        [0] => Array
            (
                [打順] => 1
                [守備] => 遊
                [名前] => 川﨑
                [打率] => .271
                [HR] => 1
                [打点] => 37
            )
    
        [1] => Array
            (
                [打順] => 2
                [守備] => 二
                [名前] => 本多
                [打率] => 303
                [HR] => 0
                [打点] => 43
            )
    
        [2] => Array
            (
                [打順] => 3
                [守備] => 左
                [名前] => 内川
                [打率] => .341
                [HR] => 12
                [打点] => 73
            )
    
        [3] => Array
            (
                [打順] => 4
                [守備] => 三
                [名前] => 松田
                [打率] => .283
                [HR] => 25
                [打点] => 83
            )
    
        [4] => Array
            (
                [打順] => 5
                [守備] => 中
                [名前] => 長谷川
                [打率] => .293
                [HR] => 4
                [打点] => 34
            )
    
        [5] => Array
            (
                [打順] => 6
                [守備] => 右
                [名前] => 福田
                [打率] => .256
                [HR] => 1
                [打点] => 20
            )
    
        [6] => Array
            (
                [打順] => 7
                [守備] => DH
                [名前] => 柴原
                [打率] => .077
                [HR] => 0
                [打点] => 0
            )
    
        [7] => Array
            (
                [打順] => 8
                [守備] => 一
                [名前] => 明石
                [打率] => .277
                [HR] => 1
                [打点] => 12
            )
    
        [8] => Array
            (
                [打順] => 9
                [守備] => 捕
                [名前] => 山崎
                [打率] => .191
                [HR] => 0
                [打点] => 11
            )
    
        [9] => Array
            (
                [打順] => P
                [守備] => 投
                [名前] => 杉内
                [打率] => .200
                [HR] => 0
                [打点] => 3
            )
    
    )
    

    CSVの出力

    CSVの出力はコントローラでComponentを宣言して、出力したい配列を準備してアクションをたたいて完了です。(今度は同日の阪神のスタメンです・・・大阪でしたし。)

    <?php
    App::uses(&#039;AppController&#039;, &#039;Controller&#039;);
    CakePlugin::load(&#039;CsvCombine&#039;);
    
    /**
     * ParentEnquetes Controller
     *
     * @property ParentEnquete $ParentEnquete
     */
    class CsvTestsController extends AppController {
     
        var $components = array(&#039;CsvCombine.CsvExport&#039;);
    
        function export(){
            $list[] = array(&#039;1&#039;,&#039;二&#039;,&#039;平野&#039;,&#039;.297&#039;,&#039;1&#039;,&#039;28&#039;);
            $list[] = array(&#039;2&#039;,&#039;中&#039;,&#039;柴田&#039;,&#039;.280&#039;,&#039;0&#039;,&#039;8&#039;);
            $list[] = array(&#039;3&#039;,&#039;遊&#039;,&#039;鳥谷&#039;,&#039;.300&#039;,&#039;5&#039;,&#039;49&#039;);
            $list[] = array(&#039;4&#039;,&#039;三&#039;,&#039;新井&#039;,&#039;.274&#039;,&#039;17&#039;,&#039;89&#039;);
            $list[] = array(&#039;5&#039;,&#039;一&#039;,&#039;ブラゼル&#039;,&#039;.282&#039;,&#039;15&#039;,&#039;66&#039;);
            $list[] = array(&#039;6&#039;,&#039;右&#039;,&#039;マートン&#039;,&#039;.316&#039;,&#039;13&#039;,&#039;57&#039;);
            $list[] = array(&#039;7&#039;,&#039;左&#039;,&#039;金本&#039;,&#039;.218&#039;,&#039;12&#039;,&#039;37&#039;);
            $list[] = array(&#039;8&#039;,&#039;捕&#039;,&#039;藤井&#039;,&#039;.218&#039;,&#039;2&#039;,&#039;15&#039;);
            $list[] = array(&#039;9&#039;,&#039;投&#039;,&#039;スタンリッジ&#039;,&#039;.095&#039;,&#039;0&#039;,&#039;0&#039;);
    
            $this->CsvExport->export($list);
        }
    }

    以下のCSVが出力されます。

    1,二,平野,.297,1,28
    2,中,柴田,.280,0,8
    3,遊,鳥谷,.300,5,49
    4,三,新井,.274,17,89
    5,一,ブラゼル,.282,15,66
    6,右,マートン,.316,13,57
    7,左,金本,.218,12,37
    8,捕,藤井,.218,2,15
    9,投,スタンリッジ,.095,0,0
    

    以上が、PHPmatsuriで発表してきました、CsvCombinePluginの紹介でした。
    このプラグインは実際にはオプションで区切り文字など指定が出来ますので、TSVなどにも対応が可能です。
    GithubのREADMEに詳しく書いているのでそちらもご覧頂けたらと思います。
    よろしければお使いください!

    最後に

    このような、有意義で楽しいイベントを準備、運営していただいた皆さん。ありがとうございました。
    次も参加したいと思えるイベントでした!

    それでは、弊社二人目が明日、また書きますのでよろしくお願いします!

      はてなブックマーク - CakePHP Clickinit Pluginが意外に便利
      このエントリーをはてなブックマークに追加

      Fusic Advent Calendar発起人の小山です。
      最近はPortisheadばかり聴いています。
      さて、Fusic Advent Calendarもクリスマスバージョンが無事終わり(自分は見事に当たりませんでした)、
      エクストラステージ「日本式アドベントカレンダー」に突入しております。
      「も〜うい〜くつね〜る〜と〜」のあれです。

      ブラウザから確認

      Webシステムを作成していると、やっぱりブラウザから挙動をテストをしたりしますよね。
      その時に、便利なのがSeleniumです。
      簡単な挙動確認ならば、Selenium IDEで操作の記録をすることで、何度も同じ操作の確認を行うことができます。

      では、ユーザの新規登録はどうしますか?

      さらにメールアドレスを登録して、確認メールが来るようなテストはどうしていますか?

      一度登録してしまうともう一度そのメールアドレスは登録できなかったりしますよね。

      ブラウザから初期化

      方法はいろいろあると思います。
      データベースを直接操作してもいいですし、そもそもSeleniumを使っているならば、Selenium RCなどを利用する際にデータベースを初期化してもいいかもしれません。
      ただ、ブラウザからちょっと簡単に操作したいと思ってCakePHPのPluginを作成してみたので紹介したいと思います。

      Clickinit Plugin

      Clickinit Pluginはブラウザ側からサーバサイドで処理を実行するためのプラグインです。

      github.com/k1LoW/clickinit

      以下のようにAppContollerの$componentsに登録するだけで、まずは設置完了です。

      次に、実際にサーバサイドで行う処理を書いたスクリプトをapp/vendor/shells/に設置します。
      その時に、ファイル名の先頭には数字を付与してください。これは実行すべきファイルの判別と、実行順序を判定するために利用しています。
      (例:00-initdb.php, 01-clearcache.php)

      あとはページの左上に表示されたタブをクリックするだけで、すべてのスクリプトを実行することができます。
      スクリプトの実行はrequire()を利用しているので、CakePHPの定数やクラスなども使えます。

      たったこれだけのプラグインです。
      Clickinitはサーバのスクリプトを実行するスイッチ的なものです。
      たったこれだけですが、意外に便利です。
      例えば、データベースの初期化だけでなく、CakePHPのキャッシュを一旦削除して挙動を確認するときにも便利です。

      ブラウザから操作ができるので、開発時のSelenium IDEのテストケースに追加してもいいかもしれません。

      注意

      Clickinit Pluginはあくまで開発時に使うプラグインです
      特にサーバ内スクリプトを動かすものになりますので、デプロイ時には外すようにしましょう

      まとめ

      ブラウザからサーバ内スクリプトを実行するClickinitを紹介しました。

      ブラウザから初期化ができるだけで、意外に効率もあがります。
      もし良かったら皆さんも試してみてください。

        はてなブックマーク - CakePHP 静的コンテンツのURLについて
        このエントリーをはてなブックマークに追加

        こんにちは、一年前に買ったデニムのサイズが合わなくなってきた島田です。

        皆さん食べ過ぎには注意しましょう。。。
        (俺が悪いんじゃない、会社周辺に美味しいお店が多いからいけないんだ!!)

        では、早速本題。

        CakePHP環境下で静的コンテンツは、通常『インストールフォルダ/app/webroot』の配下に設置しますよね。

        /app/webroot/test/index.html

        にファイルを設置すれば、

        example.com/test/index.html
        example.com/test/

        といった感じのURLでアクセスできます。

        ではこの状態で、 example.com/test (『/』なし)にアクセスするとどうでしょう?

        どん!

        example.com/app/webroot/test/

        そうなんです。

        『/app/webroot/』 が付いた状態にリダイレクトされちゃうんです。
        mod_rewite をとおさず直接アクセスしてますねぇ。

        画像やCSSファイルへのパスは、相対的位置関係が変わらないので、表示が崩れるということはありませんが、なんだか気持ち悪い。。。
        同じ情報のページに2URLからアクセス出来るのはSEO的に良くないし、
        Google Analytics などでアクセスログを取得しているときは、同一コンテンツなのに集計結果がわかれてしまう。。。

        ということで、こいつを解決しちゃいます。

        まずは Apache のログを見てみよう

        問題の解決に移る前にまず Apache のログを見てみましょう。

        192.168.0.1 - - [19/Dec/2010:23:08:06 +0900] "GET /test HTTP/1.1" 301 354 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4"
        192.168.0.1 - - [19/Dec/2010:23:08:07 +0900] "GET /app/webroot/test/ HTTP/1.1" 200 928 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4"

        301エラーを返したあとで、『/app/webroot/test/』にリダイレクトしています。

        簡単にいうとこんな感じです。

        1. スラッシュなしでアクセスしたため、Apache がファイルとして『test』を検索
        2. ファイルは見当たらなかったがディレクトリは見つかったので、クライアントに301エラーとリダイレクトメッセージ(『/』つきのURL)を返す
        3. リダイレクトメッセージにあるURLに再度リクエストを投げる
        4. コンテンツを表示

        2. で返ってくる『リダイレクトメッセージ』を直してリダイレクト先を変えてやればいいのか思いきや、
        それだと直接『example.com/app/webroot/test/』にアクセスされてしまう。。。

        というわけで、今回は

        example.com/app/webroot/test/

        に飛んできたURLを

        example.com/test/

        にリダイレクトさせるという方法で問題を解決しちゃいます。

        .htaccess を改変しよう

        CakePHP ではデフォルトで 3つの .htaccess が設置されていますが、今回は『インストールフォルダ/app/webroot/.htaccess』を改変します。

        <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
        </IfModule>

        インストール時のままだとこんな感じです。
        これをこんな感じに改変します。

        <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
        RewriteCond %{THE_REQUEST} "^(.+?) (.*?)/app/webroot/(.*?) (.+?)$"
        RewriteRule ^(.*?)$ %2/%3 [R=301,L]

        </IfModule>

        THE_REQUEST とは 先程のログの 『”GET /app/webroot/test/ HTTP/1.1″』 の部分を返します。
        要するにホストネーム以下のURLに /app/webroot/ が含まれていたら、それを省いたものへリダイレクトすると書かれています。

        Apache のログはこんな感じ

        192.168.0.1 - - [19/Dec/2010:23:18:06 +0900] "GET /test HTTP/1.1" 301 354 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4"
        192.168.0.1 - - [19/Dec/2010:23:18:06 +0900] "GET /app/webroot/test/ HTTP/1.1" 301 342 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4"
        192.168.0.1 - - [19/Dec/2010:23:18:07 +0900] "GET /test/ HTTP/1.1" 200 928 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ja-jp) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4"

        二回リダイレクトして目的のURLにたどりついているのがわかります。

        最後に

        今回の解法は、Rewriteの条件を追加していますので、どうしてもその部分にコストが追加でかかってしまいます。
        レスポンススピードをシビアに求められるコンテンツには向かない場合もありますので、注意してください。

        それでは、また次回お会いしましょう。
        さようなら。

        追記

        RewriteRule でURLを書き換えた時、自動的に URLエンコード が行われてしまいます。
        クエリ文字列に特殊文字を含む場合、意図しないURLに書き変わってしまいますので、 NEフラグを指定してエンコードを行わないようにした方がよいでしょう。

        <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
        RewriteCond %{THE_REQUEST} "^(.+?) (.*?)/app/webroot/(.*?) (.+?)$"
        RewriteRule ^(.*?)$ %2/%3 [R=301,L,NE]

        </IfModule>