PHP

ついに今日から25日まで続くAdvent Calenderが始まりました。 CakePHP Advent Calender2012の1日目を担当させていただく、たがみ(@DAI199)です。

Cakeを使い始めて半年程度の新米ですが、僕の知識をみなさんに共有するために今回の記事を書きたいと思います。

CakePHPアドベントカレンダー2012本家 http://www.adventar.org/calendars/40 Twitterハッシュタグ #cakeadvent2012

普段はFacebookと連携したアプリを量産しているため、今回の記事では、CakePHPとFacebookを連携し、ちょっとしたアプリを作ってみたいと思います。 デモアプリはこちら

>>> 女の子の画像一覧を見てみる

Facebookログインの実装

それでは早速Facebookログインを実装していきましょう。 以下のURLからFacebookSDKをダウンロードします。 >>> https://github.com/facebook/facebook-php-sdk

それをインストールしたCakePHPのapp/Vendorフォルダに入れます。ここではフォルダ名は「facebook」へ変更しました。

次に「AppController.php」に以下のコードを書きます。ここでやっていることは、Facebookに接続することと、Facebookでログイン出来たことを確認するためにSessionに書き込むことです。

<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
    public $facebook;
    public $helper = array('Html', 'Form', 'Session');

    function beforeFilter(){
        App::import('Vendor', 'facebook/src/facebook');
        $this->facebook = new Facebook( array(
                        'appId' => 'APPID',
                        'secret' => 'APPSECRET',
                        'cookie' => true 
                        ));

    }

    // Facebookで接続するときにOAuthを通す
    public function authFacebook() {
        $login_url = $this->facebook->getLoginUrl(array('scope' => 'email,publish_stream,user_birthday,user_education_history,user_likes'));
        $this->redirect($login_url);
    }

    public function connectFb(){
        $fb = $this->facebook->getUser();
        if(empty($fb)){
            $this->authFacebook();
        }
        $this->Session->write('Facebook.id', $fb);
    }
}

上記のコードのAPPID,APPSECRETの部分はFacebookアプリを作成していれてください。 Facebookアプリを作成するためには以下のURLから作成します。 >>> https://developers.facebook.com/

これでFacebookログインが実装出来ました。

Graph APIを叩く

初期画面でFacebookログインボタンを表示して、クリックするとdisplayのほうへリダイレクトされます。 以下コードになります。

【Controller】 FacebookController.php

<?php
class FacebookController extends AppController {
    public function index(){
        if($this->request->is('post')){
            $this->redirect(array('action'=>'display'));
        }
    }

    public function display(){
        // Facebookへ接続
        $this->connectFb();
        $fb = $this->facebook->getUser();

        // Friend List を取得
        try {
            $me = $this->facebook->api('/me');
            $friend_list = $this->facebook->api("{$fb}/friends?fields=gender");
        } catch (FacebookApiException $e){
            error_log($e);
        }
        $this->set(compact('fb'));
        $this->set(compact('me'));
        $this->set(compact('friend_list'));
    }
}

Viewのほうはこんな感じに書いてみました。

【View】 index.ctp

<form action="<?php echo $this->Html->url(array('action'=>'index'));?>" method="post">
    <button>Facebookログイン</button>
</form>

display.ctp

<h1>自分の顔</h1>
<img src="https://graph.facebook.com/<?php echo $fb;?>/picture?width=150" alt="" />

<h2>異性の顔((´^ω^))</h2>
<?php for($i=0; $i < count($friend_list['data']); $i++):?>
    <?php if($me['gender'] != $friend_list['data'][$i]['gender']):?>
        <a href="https://www.facebook.com/<?php echo $friend_list['data'][$i]['id'];?>">
            <img src="https://graph.facebook.com/<?php echo $friend_list['data'][$i]['id'];?>/picture?width=100&height=100" alt="" />
        </a>
    <?php endif;?>
<?php endfor;?>

以上のコードによりGraphAPIを叩くことが出来ました。 GraphAPIについては、Facebookの公式ドキュメントを読むとよいです。

女の子一覧を見てうはうは

さて、それではログインしてみましょう。 自分の友達の女の子でもうはうはです。 あ、もちろん女性の方は男性が表示されます。 女性の方が女性を見たい場合は、Viewの部分をちょちょっといじると出来ますよ。

デモはこちら >>> 女の子一覧を見てうはうは

最後に

すごい簡単なアプリですが、Facebookを使ったアプリを作ったことがない人にとっては新鮮なのではないでしょうか。 これをもう少し改良すれば異性を解析するアプリを作ったり本格的なアプリも出来そうですね。

初めてのAdventCalenderで緊張していますが、わかりにくいこと、間違っているとこ、こうしたほうがいいよ!ってとこがあればぜひコメントを残してくださるとありがたいです。

CakePHP AdventCalender2012 2日目の担当は、@fukayatsuさんです。よろしくお願いします!!

Read more

僕が最初にプログラミングを始めたころ、最初に手にとった本の中でPEARが使われていました。 ただ、本当に学び始めたころってパスを通すってのもわけがわからないしPEARで何が便利になるのかわかりませんでした。 また、その影響もあってか、PEARは難しいもの、として今の今まで避けてきました。

しかし、さすがにそろそろPHPUnit使ってテストコード書いていかないと最近のプログラマーではないよな、と思い、今回はさくらVPSにPEARを導入し、PHPUnitを動かしてみるところまで行なってみます。

それでは始めましょう。

PEARをインストールする

PEARはすごい簡単にインストールすることが出来ます。

yumが使える環境では以下のコマンドで一発です。

$ yum -y install php-pear

yumが使えない環境の場合は、以下の記事を参考にしてみてください。

>>> PEAR パッケージマネージャの取得とインストール

PHPUnitをPEAR経由でインストールする

PEARをインストールすることが出来たら、今度はPHPUnitをインストールしましょう。 以下の2つのコマンドを打ち込むだけでインストール出来ます。

$ pear config-set auto_discover 1
$ pear install pear.phpunit.de/PHPUnit

インストールされているか確認しましょう。

$ pear list
Installed packages, channel pear.php.net:
=========================================
Package          Version State
PEAR             1.9.4   stable
PHPUnit          1.3.2   stable

インストールすることが出来ました。

PHPのinclude_pathを通す

僕はここで2時間つまりました。

ここで何がしたいかというと、PHPファイルの中でrequire_onceしたときにPEARでインストールしたパッケージを読み込めるようにするということです。 そのためにはまずPEARでインストールしたファイルがどこにあるのか確認しましょう。

$ pear config-show
Configuration (channel pear.php.net):
=====================================
...
PEAR directory                 php_dir          /usr/share/pear
...

色々設定が出てきますが、「PEAR directory」という部分を探してください。 そこに書いてある部分にパスを通していきます。 僕の場合だと、「/usr/share/pear」にパスを通すべきだということがわかりました。

次に、php.iniの設定を変更します。 php.ini内に include_path という部分があるので、そこに上で確認したパスを追加してあげます。

$ vim /etc/php.ini
....
include_path = ".:/usr/share/pear"
....

追加して保存したらapacheを再起動してPHPを再読み込みしましょう。 以下を実行して、動けばOKです。

$ phpunit
PHPUnit 3.7.7 by Sebastian Bergmann.

Usage: phpunit [switches] UnitTest [UnitTest.php]
       phpunit [switches] 

.....

これでPHPUnitを使用する準備を整えることが出来ました!!

終わりに

最初はPEARがどのディレクトリに入っているのかを探すのにとても苦労しました。 また、include_pathを変更する!と気づいてから更に1時間くらい悩みました。 これは、include_pathの書き方をコロン(:)ではなくセミコロン(;)にしていたので動きませんでした。 この区切り文字は環境によって変わるらしいのでもし動かない場合は何個か試してみるとよいかもしれません。

しかしPEAR、便利ですね。昔のPEARは難しいと思っていた僕から相当成長したのだなぁと感じます。

Read more

今までCakePHPを使用してきて、ページ送りを実装したことがなかったのですが、今回実装する機会がありましたのでそれをまとめようと思います。 ページ送りというのは以下のようなやつです。

検索結果とかによく実装されているやつですね。

ただこれを自分で実装しようとすると、自分で全て計算し、例えば10件表示させようと思ってるけど、少し足りない場合はどうするか、とか色々面倒なことになってしまいます。 そこでCakePHPに準備されている、PaginatorヘルパーとPaginatorコンポーネントでさくっとページ送りを実装していこうと思います。

今回作成するページ送りは主に検索結果を表示することを想定して作っています。

まずは検索ボックスとなるビューを作成しましょう。

View/Posts/search.ctp

<?php
echo $this->Form->create('Post', array(
    'url'=>array('controller'=>'posts','action'=>'search','type'=>'get')); 
echo $this->Form->input('title');
echo $this->Form->end('Search');

次にGETで送信された値を検索してみましょう。 例えば以下のようにControllerを書きます。

Controller/PostsController.php

<?php
class PostsController extends AppController {
    public $helpers = array('Html', 'Form', 'Paginator');
    public $components = array('Paginator');

    public function search() {
        // 前回検索した値を常に保存しておく
        $this->request->data['Post'] = $this->request->query['Post'];

        // Viewに値を渡す
        $this->set('results', $this->paginate('Post', array(
                'post_name LIKE' => "%{$this->request->data['Post']}%")));

あとはビューで結果を表示するだけです。 以下のようにしましょう。

View/Posts/search.ctp

<?php
echo $this->Paginator->prev('前へ');
echo $this->Paginator->numbers();
echo $this->Paginator->next('次へ');

foreach($results as $result) {
    // 処理を書く
}

これで以下のようなページ送りを実装することが出来ました。

この状態では次のようなURLになっていると思います。

/posts/search/page:3?title=hogehoge

それを以下のようなURLにしましょう。

/posts/search?title=hogehoge&page=3

次のコードをControllerに書きましょう。

$this->Paginator->settings['paramType'] = 'querystring';

これでURLがGET風になりました!

以下が参考にした記事です。

参考

Pagination – CakePHP公式ドキュメント(英語)

Read more

簡単にCSVダウンロードが可能になるCSVヘルパーの作成方法をまとめます。

ここに貼ってあるコードは僕のgithubからダウンロード出来ます。
>> cakephp-csv-helper – github

それでは使い方を紹介します。

まずはCsvHelper.phpを作成しましょう。
app/View/Helper 以下に CsvHelper.phpとして以下のコードをコピペしましょう。

<?php
class CsvHelper extends AppHelper {

    var $delimiter = ',';
    var $enclosure = '"';
    var $filename = 'Export.csv';
    var $line = array();
    var $buffer;

    function CsvHelper() {
        $this->clear();
    }

    function clear() {
        $this->line = array();
        $this->buffer = fopen('php://temp/maxmemory:'.(5*1024*1024), 'r+');
    }

    function addField($value) {
        $this->line[] = $value;
    }

    function endRow() {
        $this->addRow($this->line);
        $this->line = array();
    }

    function addRow($row) {
        fputcsv($this->buffer, $row, $this->delimiter, $this->enclosure);
    }

    function renderHeaders() {
        header("Content-type:application/vnd.ms-excel");
        header("Content-disposition:attachment;filename=".$this->filename);
    }

    function setFilename($filename) {
        $this->filename = $filename;
        if (strtolower(substr($this->filename, -4)) != '.csv') {
            $this->filename .= '.csv';
        }
    }

    function render($outputHeaders = true, $to_encoding = null, $from_encoding = "auto") {
        if ($outputHeaders) {
            if (is_string($outputHeaders)) {
                $this->setFilename($outputHeaders);
            }
            $this->renderHeaders();
        }
        rewind($this->buffer);
        $output = stream_get_contents($this->buffer);
        if ($to_encoding) {
            $output = mb_convert_encoding($output, $to_encoding, $from_encoding);
        }
        return $this->output($output);
    }
}

コピペ出来ましたか?
次にやることとしては、CSVダウンロードを行いたいControllerでメソッドを作成します。

このときの注意としては、さきほど作った CsvHelper.php を先頭で読み込んでおきましょう。
※ここでは UsersController.php としてファイルを作成しています。

<?php
class UsersController extends AppController {
    var $name = 'Users';
    // Csvヘルパーを読み込む
    var $helpers = array('Html', 'Form', 'Csv');

    function download_csv() {
        $this->layout = false;
        $filename = 'Csvダウンロード_'.date('YmdHis');
        $genders = array('1' => '男性', '2' => '女性');
        // 表の一行目を作成
        $th = array('id', 'username', 'gender', 'status');
        // 表の内容を取得
        $td = $this->User->find('all', array('fields' => $th));
        $this->set(compact('filename', 'genders', 'th', 'td'));
    }
}

最後にビューを作成します。 app/View/Users/download_csv.ctp として保存しています。

<?php
$this->Csv->addRow($th);
foreach($td as $t) {
    $this->Csv->addField($t['User']);
    // .... 行を追加していく
    $this->Csv->endRow();
}
$this->Csv->setFilename($filename);
// 文字化けの場合は echo $this->Csv->render(true, 'sjis', 'utf-8');
echo $this->Csv->render();

これで完成です! もしCSVファイルが文字化けしている場合は、 ビューの最後のrender()を

echo $this->Csv->render(true, 'sjis', 'utf-8');

に直すとなおります。

最後にまとめてコードをダウンロード出来るようにもう一度githubのURLを貼っておきます。 何か間違いなどありましたらpushしていただけるとありがたいです。

>> cakephp-csv-helper – github

この記事を読んでいるあなたにおすすめ!

CakePHPをやっているのであればこれは必読です!

CakePHP2 実践入門 (WEB+DB PRESS plus)
安藤 祐介 岸田 健一郎 新原 雅司 市川 快 渡辺 一宏 鈴木 則夫
技術評論社
売り上げランキング: 11,668
Read more

この記事はSMASHING HUBに掲載された 6 Commodious PHP Functions for Beginners の内容を日本語訳したものです。

PHPは公式リファレンスページで5000以上の主要な関数を用意しています。その膨大なリファレンスページの中には、開発者になったばかりの人が見ておくべきヒントやコツがたくさんつまっています。

その中から重要だと思われる部分を抜き出して記事にしています。

1, わかりにくい === 演算子

PHPは強力かつスマートな言語です。また、変数型が緩く型付けされた言語してよく知られています。ただ、そのせいか、多くの人が == と === の使い方について混乱しているのをリファレンスやブログのコメントから気づきました。これらはどう違うのでしょうか。

PHPは ‘431’を文字型として認識しますが、これをそのまま四則演算で使用することも出来ます。 このことはとても理にかなっています。 ただ問題が起きるのはこの数字が0の場合です。 0という数字は、0やfalseの意味で使われます。このことにより少し不思議で複雑なことがおきます。 そこで、=== を使用すると簡単にどちらの意味で使われているのか判断することが出来ます。

他の似たような言語では、== は変数を比較することに使われてることが多いですが、数字の0として比較したいとき、PHPではそれを数字の0として認識せずにfalseとして認識するかもしれません。 こういうときこそ、まさに === を使うべきタイミングです。 === は変数の値を比べるだけじゃなく、型まで調べます。 この演算子は数字の0かどうかを確定させたいときに使います。

使い方:

$myVar = false;

// true
if($myVar == 0) {}

// false
if($myVar === 0) {}

2, アプリケーションの中でグラバターを使う

グラバターとは?
これは読者を手助けし、共有する価値のあるものだと思った抜粋のうちの1つです。WordPressの絶大な人気も、グラバターの使用によってもらたされたものです。グラバターは綺麗はAPIを提供し、簡単に統合して使うことが出来ます。

/*
-myEmail- Email address to show gravatar for
-gSize - size of gravatar
-url - URL of default gravatar to use
-gRating - rating of Gravatar(G, PG, R, X)
*/
function myGravatar($myEmail, $gSize, $url, $gRating)
{
    echo '<img src="http://www.gravatar.com/avatar.php?gravatar_id='.md5($myEmail). '&default='.$url.'&size='.$gSize.'&rating='.$gRating.'" alt="" width="'.$gSize.'px" height="'.$gSize.'px" />';
}

一度、上記の関数を追加すれば、グラバターの画像を表示させたい部分のどこでも呼び出すことが出来ます。

myGravatar($myEmail, $gSize, $url, $gRating);

3, Empty()

他の言語ではほとんど使われることのない手軽なPHP関数の1つがempty()関数です。 この関数は使われる文脈により、違う動きをします。 この関数が実際に何をしているかは、変数が定義されていない場合と、何かの値を持っているときを調べてみるとわかります。 また、null,false,数字の0を調べて、返り値であるtrueかfalseを調べます。

if(!empty($_GET['myVal'])){

$myVar = $_GET['myVal'];

}else{

$myVar = 'SmashingHub';

}

// Or something like below does the same job

$myVar = 'SmashingHub';

if(!empty($_GET['myVal'])){

$myVar = $_GET['myVal'];

}

4, Function_exists()

この関数は、特定の名前の関数が存在しないかどうかをチェックします。 WordPressのようなCMSを触るとき、多くのプラグインとたくさんの関数が統合されています。実際に試してみましょう。

私のブログテーマを変更したとき、問題が発生しました。サイドバーにいくつかの未定義の関数エラーが発生しました。 いくつかのソースコードをみて、既に定義されている同じ関数を発見しました。

テーマ開発者は、下のサンプルのように、function_exists()を使用して既にインストールしているプラグインの中に同名の関数がないかどうか調べるべきです。

悪い例:

get_flickrrss();

良い例:

if (function_exists('get_flickrrss')) {

get_flickrrss();

}

5, 参照

参照は、返り値を持たず、グローバル変数を設置することなく関数に変数を渡すことが出来ます。 この方法は、元々の変数を変えることも出来ます。関数の始めに、「&」を使います。

例:

function lowercase(&$myString){

$myString= strtoupper($myString);

}

$myName = 'smashinghub';

lowercase($myName);

echo $myName;  // returns SMASHINGHUB

上記の例では、strtoupper()関数を呼び出し、$myNameに値を渡して、実際の文字列を変更しています。

6, Similar_text

PHPは類似の2つの文字列をチェックするsimilar_text機能を持っています。

similar_text($myVar1, $myVar2, $sPercent);
// どのくらい似ているかをパーセンテージで返します
この記事はSMASHING HUBに掲載された 6 Commodious PHP Functions for Beginners の内容を日本語訳したものです。
Read more

CakePHPでアプリケーションを組むのはとても楽ですよね。 しかも先人の方が残してくれたプラグインが大量にあるので何かやりたいときにまずプラグインを検索すればいいので本当に助かりますよね。

今回はCakePHPで出力されるエラー画面を編集していきます。 CakePHPをインストールしたままのデフォルトの状態だと存在しないコントローラーとかアクションにアクセスしようとするとエラーメッセージが出ますよね。 コントローラーがありませーんとか。 ここをいじっていきます!

CakePHPでは開発用モード、本番環境モードなどを切り替えることが出来ます。 app/Config/core.php

Configure::write('debug', 2);

と書いてある部分があると思います。
ここの”2″というのがデバッグモードです。この数字を”0″にすると本番環境モードになり、エラーメッセージも最小限しか出ないようになります。
実際に切り替えて見るとエラーメッセージが変化することがわかります。

開発用モードの表示方法を変更したいかもしれませんがそれはまた今度まとめたいと思います。
今回は本番環境のエラー画面を変更します。
変更しますというか変更出来るように知識をつけていきましょう。

CakePHPのデフォルトの緑画面のCSSはどこにあるのか、出力しているHTMLはどこかというのを知っておきましょう。

CSSはapp/webroot/css/cake.generic.css というファイルがあります。
ここでデフォルト画面のCSSが定義されています。
なのでこのCSSを一度消してしまいましょう。もし元の画面に戻したくなったら githubからダウンロードしてくればいいので大丈夫です。

消しましたか?
それではさきほどの画面を見てみましょう。

このように真っ白な画面になったと思います。これでデフォルト画面のCSSはcake.generic.cssだったことがわかりました。

ここまできた人は、「じゃぁcake.generic.cssを定義してるのはどこだよ!」と石を投げる勢いで感じることだと思いますが、もちろん定義してある場所はあります。

app/View/Layouts/default.ctp

<?php echo $this->Html->css('cake.generic');

と書いてある部分があります。ここでCSSを定義していたのですね。 そしてこのdefault.ctpがエラー画面のレイアウトになります。レイアウトを変えたい場合はここをいじりましょう。 それではレイアウトを少しいじってみましょう。

今回はエラー画面の下にあるcakephpの画像を消したいと思います。

app/View/Layouts/default.ctp に以下のようなコードがあります。これを全て消してしまいましょう。

<div id="footer">
<?php echo $this->Html->link(
    $this->Html->image('cake.power.gif', array('alt' => $cakeDescription, 'border' => '0')),
    'http://www.cakephp.org/',
    array('target' => '_blank', 'escape' => false)
        );
?>
</div>

どうなりましたか?ちゃんと消えましたか?
以下のようにしっかり消えます。

これでレイアウトファイルの場所、CSSの場所も理解出来たと思います。

あとはレイアウトに流し込まれるコンテンツはどこにあるかということです。

コンテンツは、app/View/Errors/にあります。

それでは少しいじってみましょう。 error400.ctp に書いていきます。 今のままだと英語表記なので日本語にしてみましょう。

<p class="error">
    <strong><?php echo __d('cake', 'エラー'); ?>: </strong>
    <?php printf(
        __d('cake', 'そのURLはこのサーバー上には存在しません:%s'),
        "<strong>'{$url}'</strong>"
    ); ?>
</p>

これで更新すると以下のように日本語化されました。

これでほとんどのことが出来るようになったと思います。
エラー画面もおしゃれに設定して綺麗なアプリケーションを作成しましょう。

参考

exception – CakePHP公式ドキュメント

Read more

CakePHP2を使おうと思ったときにおそらく1番最初にやることといえば公式ドキュメントを読んでブログチュートリアルを行うことだと思います。

ただこのブログチュートリアルは、CakePHPってこんなにすごいんだぜ! っていうのを強調したいためか、ある程度自動的にモデルと接続したりバリデーションが出来たりしています。

今回僕が少しつまった部分はバリデーションの部分です。

チュートリアルでは $validate に条件を書けば勝手にバリデーションしてくれますが、実際に運用する場合は自動的にバリデーションを行うというよりはむしろ明示的にバリデーションを行ないたいと思うことも多いと思います。

結論をいうと

Modelの関数であるvalidates()関数を使用する

ことで解決出来ます。

以下に例を示しましょう。

PostsControllerに以下のようなコードが書いてあるとします。

<?php
class PostsController extends AppController {

    public function index(){
        if($this->request->data){
            // ここにバリデーションをかけたあとに色んな処理をしたい
        }
    }

バリデーションをしたいのでモデルにバリデーションを書きます。
ただし今回は自動でバリデーションしないように、Userモデルにバリデーションを書きたいと思います。

<?php
class User extends AppModel {
    public $name = 'User';

    public $validate = array(
        'name' => array(
            'rule' => array('notEmpty'),
            'message' => '空にしないでくださいっ!!'
        )
    );
}

バリデーションに関しては公式ドキュメントを参照してください。

ここに書いたバリデーションをさっき書いたPostsControllerでバリデーションを使用したいとします。
その場合は以下のように書けばUserモデルのバリデーションを使用してバリデーションを行うことが出来ます。

<?php
class PostsController extends AppController {

    public function index(){
        if($this->request->data){
            // ここにバリデーションをかけたあとに色んな処理をしたい
            $this->User = ClassRegistry::init('User');
            if($this->User->validates()){
                // 色んな処理を書く!
            }
        }
    }

この例からわかることは、CakePHPが自動的にやってくれてたことは全て明示的に書くことが出来るということです。

当たり前のことですが、意外とここが理解できなくて苦しむことが多かったです。
また、モデルはデータの入出力、コントローラーはデータの道筋、というMVCの考えがしっかりしていればどこに関数があるかなんとなく検討がつくのかな、と思います。

もし何か質問や相談、ここ違うよ!ってところがあれば以下のコメント欄、またはリプライ(@DAI199)でお願いしますっ

Read more

フレームワークはとても便利なものです。 色々な用途があるにせよ、保守性を高めたりプラグインを使用することによって難解な処理を簡単にしたりすることが出来ます。

僕は今のところスクリプト言語で主に使っているのがPHPなので、フレームワークは一般的だと思われるCakePHP2を採用しています。

ここではCakePHP2を初めて勉強し、CakePHPをうまく使いこなしていくための記事を紹介しています。

最初フレームワークを勉強したときはPHPで出来ているのにPHPとは全く違う言語だとびっくりしたものの、慣れてしまえば、「やっぱりPHPだね」と開き直ることが出来ました。ただ最初慣れるまでが辛いかもしれません。

ここに紹介している記事は僕が何度も読み返し、理解しなおし、コードを書いた記事たちばかりです。 何度も読み直し、理解すればおのずと使えるようになります。頑張りましょう。

まずは・・・

なぜCakePHPを使うのか、考えてみましょう

なぜCakePHPなのか? – ECWorks Blog

MVCとは?CakePHPとは?という部分を読みましょう

CakePHPの概要 – CakePHP公式ドキュメント

そして・・・

ブログチュートリアルで基本的な使い方を理解しましょう

ブログチュートリアル – CakePHP公式ドキュメント

そのあとは・・・

初心者向け記事で様々な事柄を少しずつ勉強しましょう

初心者向け 8時間耐久CakePHP2勉強会を開催しました – candycane development blog

8時間耐久CakePHP2勉強会の資料 – SSSSlide

3時間濃縮CakePHP2.1@札幌資料 – slideshare

慣れてきたら・・・

ベストプラクティスを勉強しましょう

何か困ったときにこういう記事を読んでおけば助かることがあります。 CakePHP1.1,1.2,1.3などの情報は、役に立たないと思いがちですが、その情報に書いてあるメソッドなどは2.x系でも実装されていることが多いです。 過去の情報もうまく利用しつつ、公式ドキュメントで検索してみて、あれば使いましょう。

CakePHPを使ったMVC設計のベストプラクティス – sooey.com

CakePHP開発者が知るべき10のこと – 1byte.jp

CakePHP Modelとの付き合い方(CakePHP Advent Calendar 2010 3日目) – Shin x blog

CakePHPで細かすぎて伝わらないtipsネタBEST3 – Knockin’on TechLog

誰でもできるサービスレイヤの実装 – 24時間CakePHP

CakePHP Best Practices: Fat Models and Skinny Controllers – bitfluxx(英語)

最後に・・・

わからないことがあればドキュメントのAPIに聞きましょう

CakePHP 公式ドキュメント

注意

よくGoogleなどで検索すると過去の情報(CakePHP1.1や1.2の情報)が出てくることがあるのですが、ここであきらめずに、使われているメソッドなどを追ってみましょう。

結局はCakePHPで実装されていることなのでもしかしたら同じメソッドが実装されている可能性があるのです。そこでしっかり公式ドキュメントに戻って検索し、ドキュメントを読むことがCakePHPを使いこなすための鍵です。

いかがでしょうか。この記事によって、あなたの力に少しでもなれれば幸いです。 もし、もっと参考になる記事があればぜひ教えてください。 以下のコメント欄、またはリプライ(@DAI199)までお願いします。

Read more

単一のフィールドでバリデーションを行うには、モデルでバリデーションを定義してやればいいのですが、複数のフィールドにかかるバリデーションはどうすればいいのかわかりませんでした。 今回取り扱う、複数のフィールドにまたがるバリデーションというのは以下のような電話番号のフィールドや名前のフィールドなどです。

1つずつフィールドにバリデーションするとエラーメッセージがいくつも出てくる

結論からいうと、

自分で関数を定義する

ことによって解決しました。 例えば、空のフィールドを許さないバリデーションを行う場合は以下のようにモデルに書くと思います。

モデル

<?php
class Posts extends AppModel {
   public $validate = array(
      'test_field' => array(
         'rule' => array('notEmpty'),
         'message' => '文字を入力してください。'
      )
   );
}

ここでruleに指定してあるnotEmptyというものは、CakePHP側で作成してある組み込み関数になります。
ちなみにnotEmptyがどこに定義してあるかは公式ドキュメントに書いてあります。

notEmpty – CakePHP公式ドキュメント

ruleに指定している部分が関数なのであれば、自分で作成しよう! ということで複数フィールドにわたるバリデーションも自作の関数を作成することで解決出来ます。
それではさきほどの画像のような、電話番号のバリデーションを行なってみましょう。

Viewに以下のように書いてあるとします。

<?php echo $this->Form->create('Post');?>
<?php echo $this->Form->text('tel1', array('label' => false));?> - 
<?php echo $this->Form->text('tel2', array('label' => false));?> - 
<?php echo $this->Form->text('tel3', array('label' => false));?>
<?php echo $this->Form->end('送信');?>

この場合、tel1,tel2,tel3それぞれにバリデーションをしてもよいのですが、tel1,tel2が空のフィールドだったりした場合、エラーメッセージが2つ表示されることになります。

モデルに全てのフィールドが空のフィールドを許さず、数字のみしか受けつけないという関数を作成し、$validateに定義します。

<?php
class Post extends AppModel {
   public $validate = array(
      'tel1' => array(
         'notEmpty' => array(
            'rule' => 'checkNotEmpty', //下に関数を定義している
            'message' => '電話番号を入力してください。'
         ),
         'custom' => array(
            'rule' => 'checkNumberAll', //下に関数を定義している
            'message' => '数字のみ入力してください。'
         )
      )
   );

   public function checkNotEmpty(){
      if(!empty($this->data['Post']['tel1']) && 
         !empty($this->data['Post']['tel2']) && 
         !empty($this->data['Post']['tel3'])) {
            return true;
      } else {
            return false;
      }
   }

   public function checkNumberAll(){
      // 数字のみ許可
      $pattern = '/^[0-9]+$/';
      $tel1 = preg_match($pattern, $this->data['Post']['tel1']);
      $tel2 = preg_match($pattern, $this->data['Post']['tel2']);
      $tel3 = preg_match($pattern, $this->data['Post']['tel3']);
      if(empty($tel1) && empty($tel2) && empty($tel3)){
         return true;
      } else {
         return false;
      }
   }
}

これで複数フィールドのバリデーションをすることが出来、エラーメッセージも1つしかはかなくなります。
$this->dataで無理やり行なっている部分を汎用性のあるものにするのが次のステップですね。
もっとよいやり方があれば教えていただきたいです。

この記事は以下のページを参考にしました。
CakePHP Users in Japanのほうのページには、汎用性のある関数が書かれているのでそれを見ながら上の関数たちを汎用性のあるものに変えていこうと思います。

参考ページ

“複数のフィールドにまたがるバリデーションは?” フォーラム – CakePHP Users in Japan

notEmpty – CakePHP公式ドキュメント

追記(2012年9月13日15:30)
公式ドキュメントにもしっかり書いてありました。。
こういうのって気づいたあとに見えるようになりますよね。。
Model – CakePHP API(validateの部分)

Read more

CakePHPを用いて多言語化をする方法をまとめます。 今のご時世、複数言語でサービスを運用するのは当たり前になりつつあります。 少なくとも1つのサービス内で、日本語、英語くらいは切り替えたいですよね。

今回はi18nを使用して多言語化をはかりたいと思います。 i18nに関しては以下のページを参考にしてみてください。

I18N【国際化】 – IT用語辞典

国際化と地域化 – Wikipedia

それでは多言語化の手順を紹介していきます。

CakePHPのインストール

まずはCakePHPをインストールしましょう。
今回はわかりやすいように

インストール→コントローラ、ビューの作成→i18nを使って多言語化

をしようと思います。
それでは以下からダウンロードしましょう。

CakePHP – github

【tmpフォルダ書き込み権限付与】
解凍してアクセス場所に置いたら、tmp/を書き込み可能にしましょう。

cd path/to/cakephp/app
chmod -R 707 tmp/

【Security.saltの更新】
適当な文字列を生成しましょう。
Config/core.php 内のSecurity.salt,Security.cipherSeed部分を更新しましょう。
いつもがちゃがちゃキーボード叩いて出来るだけランダムにしようとしています。

【データベースの設定】
今回データベースは使いませんがエラーメッセージ出てるのが気持ち悪いので適当なデータベースを設定しておきましょう。
database.php.defaultをコピーして名前をdatabase.phpに変更後、サーバー名などを入力してください。

【routes.phpの設定】
これからHogeController.phpを作成するのだが、デフォルトの状態だとPagesController.phpが表示されてしまう。
以下のように設定しよう。

Router::connect('/', array('controller' => 'hoges', 'action' => 'index'));

とりあえず準備は完了しました。

画像を見てもわかると思いますが、今回はCakePHP2.2.1を使用しています。

Controller,Viewの作成

それではControllerを作成しよう。
Controller/HogesController.phpを作成します。

<?php
class HogesController extends AppController {
        public function index(){

        }
}

特に何もしていない。
次はView。
View/Hoges/index.ctpを作成しよう。

<h2><?php echo __('Intermationalization');?></h2>
<p><?php echo __('Test now');?></p>

ここで (‘ ‘)で囲んだ部分がのちのち、i18nで翻訳する部分です。
翻訳する部分は全て
(‘ ‘)で囲もう!
__はアンダーバー2個なので注意!!

もちろん中にいれる文章が日本語でも問題ない。

※例えば翻訳したい部分に変数などが入っている場合は以下のようにするとなんとかなる。

$lang = 'Japanese';
echo sprintf(__('%s version'), $lang);

それではこれをブラウザで表示してみよう。
以下のようになる。

それではこの画面をi18nを使用して日本語表示にしてみよう。

POファイルを作成する

これからはコンソールで作業する。

cd /path/to/cakephp/Console
./cake i18n -app /path/to/cakephp/app

cakeを実行すると下記のようになる。

---------------------------------------------------------------
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)
>

POTファイルを作成するので「E」をタイプしてEnterする

What is the path you would like to extract?
[Q]uit [D]one  
[/path/to/cakephp/app/] > 

抽出元は?と聞かれるのでそのままEnterを押す

What is the path you would like to extract?
[Q]uit [D]one  
[D] > 

出力先は?と聞かれるのでこれもそのままEnterを押す

Would you like to extract the messages from the CakePHP core? (y/n) 
[n] > 

1つのファイルに翻訳ファイルをまとめるか聞かれるのでここは「y」にして1つにまとめておく。 「n」にすると別々のファイルで作成される。

出力中…

Processing /home/daiki/public_html/cakephp/app/Controller/HogesController.php...
Processing /home/daiki/public_html/cakephp/app/View/Hoges/index.ctp...
Processing /home/daiki/public_html/cakephp/app/View/Layouts/default.ctp...


Done.

完了したので「Q」を押してスクリプトから抜けだそう。 /cake/to/path/Console に default.potというファイルが出来ているはずである。 この default.pot というファイルを /cake/to/path/Locale/jpn/LC_MESSAGES/ に default.po というファイル名でコピーしよう。 途中のフォルダがない場合は作成しよう。

移動させたファイルである default.po ファイルをテキストエディタでひらいてみよう。

#: View/Hoges/index.ctp:1
msgid "Intermationalization"
msgstr ""

#: View/Hoges/index.ctp:2
msgid "Test now"
msgstr ""

msgidが元の文章、msgstrに翻訳する文章を入れる。 それでは上記のファイルに以下のように書いてみよう。

#: View/Hoges/index.ctp:1
msgid "Intermationalization"
msgstr "国際化"

#: View/Hoges/index.ctp:2
msgid "Test now"
msgstr "テストなう"

上書き保存したら、ブラウザでさきほどの画面を更新してみよう。 以下のように表示されるはずである。

やった!多言語化出来た!!

多言語化のテスト

ただこのままでは国を移動しない限り日本語で表示され続けてしまう。
これはブラウザがサーバーに送信するヘッダー情報から言語情報を抜き出してCakePHPが判断しているからである。
それでは日本にいながら英語を表示するためにはどうしたらいいのか。
以下の関数をAppController.phpのbeforeFilter()にでも書けば英語に戻る。

function beforeFilter() {
    Configure::write('Config.language', 'en');
}

更新してみよう。ほら、英語にもどった!

さて、ここまで作業をした人は気づいたことだろう。
/cake/to/path/Locale に作成した英語のPOファイルを格納するフォルダ名は eng
しかし日本語にするためには Configure::write で指定するときは en
になる。
つまりフォルダ名と関数に指定するものが違うのである。

これはどこで指定しているかというと、 /cake/to/path/lib/Cake/I18n/L10n.php の $_l10nMap で指定してある。
ここでは配列で指定してあるが、キーがLocale内のフォルダ名、値が Configure::writeで指定する文字列となる。

つまりまとめるとこうなる。

例えば中国語を新たに追加するとする。
/cake/to/path/lib/Cake/I18n/L10n.php の $_l10nMapを見てみると中国語は以下のように書いてある。

/* Chinese */ ‘chi’ => ‘zh’,

よって、

◯ /cake/to/path/Locale/chi/LC_MESSAGES を作成し default.poをコピー ◯ テストする場合は Configure::write(‘Config.language’,’zh’);

以下に使うことが多いとおもわれるものをリスト化しておく。参考にしてほしい。

/* Chinese */ ‘chi’ => ‘zh’(英語でChinese)
/* Chinese */ ‘zho’ => ‘zh’(中国語でZhongwen)
/* English */ ‘eng’ => ‘en’
/* French (Standard) */ ‘fre’ => ‘fr’
/* French (Standard) */ ‘fra’ => ‘fr’
/* Japanese */ ‘jpn’ => ‘ja’

これで多言語化は完璧なはず!

もしよかったらいいね!またはツイートを押していただけると嬉しいです。

Read more