PHP

みなさんこんにちは!

ついにCakePHP3のdev preview 1が出ましたね! CakePHP 3.0.0 dev preview 1 released

テンション上がったので少しですが試してみようと思います。 CakePHP自体の開発スピードが最近上がってきたと感じるのでわくわくしてます。 それでは一緒にいじっていきましょう!

CakePHP3をインストールする

CakePHP3からComposerが必須になったのでComposerからインストールします。

$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar create-project -s dev cakephp/app .

これでインストール完了です!簡単!ひゃっほーい!

CakePHP2からはdatabase.phpがなくなり、app.phpに統合されたのでapp.phpからデータベースの設定を行いましょう。 これでとりあえずインストール完了です。 おそらくCakePHP3の安定版ではデータベース設定もbake出来るとは思うのですが今のところbakeが動かないようなので手動で設定しました。

これでいつもの緑画面が出てきたと思います。(DebugKitは気分的に入れてみました。オールグリーン、気持ちいいので)

データベースには以下のテーブルとデータを挿入しました。

CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `content` text NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ;

INSERT INTO `posts` (`id`, `title`, `content`, `created`, `modified`) VALUES
(1, 'test1', 'test1の内容です', NOW(), NOW()),
(2, 'test2', 'test2の内容です', NOW(), NOW()),
(3, 'test3', 'test3の内容です', NOW(), NOW());

次で実際に触ってみます。

コードを書いてみる

今回やることはさきほど入れたデータを表示したりCakePHP3から実装されたEntityやRepositoryを使って遅延評価を行ったりしてみたいなぁと思います。

それでは早速書いていきましょう。

まずはPostsController.phpから書いていきます。

PostsController.php

set('posts', TableRegistry::get('Posts')->find('all'));
    }
}

namespaceとかuse使ってる部分がモダンw 見ればわかるとは思いますが、Postsテーブルのインスタンスを作り、全件取得しています。 それをViewにpostsという変数名でオブジェクトを流し込んでいます。 namespaceにはそのファイルの場所名を書きます。今回のControllerであればApp/Controller以下にあるので上記のようになっています。

それではModelを書いていきましょう。 僕もまだEntityやRepositoryは厳密にどのようなものか理解出来ていないのですが、Entityにはモデルのロジックを、Repositoryにはデータベースのリレーションやバリデーションを書いていくようです。(あんまわかってない。誰か教えて!)

まずRepositoryのほうから作ります。

App/Model/Repository/PostsTable.php

<?php namespace App\Model\Repository;

use Cake\ORM\Table;

class PostsTable extends Table {

}

今回はリレーションやバリデーションはかけないので何も書きません。 次にEntity

App/Model/Entity/Post.php

<?php namespace App\Model\Entity;

use Cake\ORM\Entity;

class Post extends Entity {

}

Entityのほうには後から関数を定義してみようと思います。

そして最後にView これでとりあえず動くはずです。

App/View/Posts/index.ctp


    id;?>

これで以下の画像のように数字が出てくるはずです。

foreach$postsをイテレートしてidを表示してみました。もちろんidの部分をtitlecontentに変えればそれを表示することが出来ます。

Viewに渡されたオブジェクトからEntityモデルを叩く

今回はViewに$postsという変数名でオブジェクトを渡しましたが、ここからPostEntityを叩くことが出来ます。

App/Model/Entity/Post.phpにメソッドを追加します。

App/Model/Entity/Post.php

public function getFullContent(){
    return $this->_properties['title'] . ":" . $this->_properties['content'];
}

そしてViewも変えます。

App/View/Posts/index.ctp


    full_content . "
";?>

これで以下のような表示が出来ます。

Entityのほうでgetから始めた関数はViewのオブジェクト側でgetを除いたアンダースコア記法で呼び出せるのです! これ超ベンリ!感動しちゃいました。Railsの感覚に近い。。

最後に

僕も対してわかっていないのでとりあえず動かしてみてこういうことが出来る、こういうことが出来なくなった、というのを1つずつ確認している段階です。 また開発バージョンなのでこれから変更がかかる可能性があります。 開発が終わるのがいつになるかわかりませんが、少しずつでも追っかけていると移行が早く出来て便利かもしれませんね!

CakePHPをこれから始めたい人は持っておくといいかも

Webアプリ開発を加速する CakePHP2定番レシピ119
長谷川 智希
秀和システム
売り上げランキング: 65,741
Read more

みなさんこんにちは!

今日ついにCakePHP3のdev preview 1が出ましたね! CakePHP 3.0.0 dev preview 1 released

ということで早速インストール・・・しようと思ったのですが色々つまづいたのでメモ

PHPのバージョンにあわせてmcryptを入れる

なにはともあれhomebrewでlibmcryptをインストールしましょう。 以下のコマンドを実行

$ brew install mcrypt

そのあとにそれぞれのローカルにインストールされているPHPのバージョンに合わせてソースを公式からひろってきましょう。 自分は5.4.17だったので5.4.17のソースをひろってきてます。

$ curl --location -s http://museum.php.net/php5/php-5.4.17.tar.gz
$ tar zxvf php-5.4.17.tar.gz
$ cd php-5.4.17

そしてコンパイル & インストール

$ phpize
$ ./configure
$ make -j6
$ make test
$ sudo make install
$ sudo vi /etc/php.ini
# => 'extension=mcrypt.so' を追記
$ sudo apachectl restart

そして最後にインストール出来ているか確認しましょう。

$ php -i | grep -i mcrypt

# mcrypt_supportがenabledになっていればOK!

最後に

わくわくしながらCakePHP3で遊ぼうとか思ってたらここだけで2時間くらいたっちゃって疲れちゃったよ・・・ 明日こそはCakePHP3で遊ぼうと思います!

PHP使うなら持ってていいと思ふ

PHP逆引きレシピ 第2版 (PROGRAMMER’S RECiPE)
鈴木 憲治 山田 直明 山本 義之 浅野 仁 櫻井 雄大 安藤 建一
翔泳社
売り上げランキング: 9,037
Read more

みなさんこんにちは!!

以前CakePHPとWordPressでアプリを組んだのでリレーションとか色々書いていこうと思います。 WordPressではデータを入力、保存するのみで、主なデータ表示はCakePHPで行いました。

WordPressのデータをCakePHPで取得するために設定する

CakePHPとWordPressはインストール済み、また記事は何個か入っている、タグも何個か設定してある前提でやっていきます。

今回やるのは「記事からその記事に結びついているタグを表示する」ことと「タグからそのタグが結びついている記事を表示する」ことです。 自分でもちょっとおかしいと思うところは結構ありますw

WordPressのデータベースの構造は以下を見ればわかります。 http://wpdocs.sourceforge.jp/データベース構造

CakePHPではきつそうな部分が混ざってますがそこはスルーしましょう。 ここでやりたいことは記事に対するタグを引っ張ってくることです。

それではやっていきましょう。 いじっていくテーブルは、wp_postswp_term_relationshipswp_term_taxonomywp_termsの4つです。 なのでそれに対応するModelを作っていきます。

wp_postswp_term_relationshipsを持っているので以下のように書きます。

Posts.php

App::uses('AppModel', 'Model');

class Post extends AppModel {

    public $primaryKey = 'ID';

    public $useTable = 'wp_posts';

    public $name = 'Post';

    public $tablePrefix = 'wp_';

    public $hasMany = array(
        'TermRelationship' => [
            'className' => 'TermRelationship',
            'foreignKey' => 'object_id'
        ]
    );
}

wp_term_relationshipsはこんな感じです。ちょっとつっこみたいのはよくわかる。。。

TermRelationship.php

App::uses('AppModel', 'Model');

class TermRelationship extends AppModel {

    public $useTable = 'wp_term_relationships';

    public $name = 'TermRelationship';

    public $tablePrefix = 'wp_';

    public $belongsTo = [
        'TermTaxonomy' => [
            'className' => 'WpTermTaxonomy',
            'foreignKey' => 'term_taxonomy_id',
        ]
    ];
}   

wp_term_taxonomy

TermTaxonomy.php

App::uses('AppModel', 'Model');
class WpTermTaxonomy extends AppModel {

    public $name = 'TermTaxonomy';

    public $useTable = 'wp_term_taxonomy';

    public $primaryKey = 'term_taxonomy_id';

    public $tablePrefix = 'wp_';

    public $belongsTo = [
        'WpTerm' => [
            'className' => 'WpTerm',
            'foreignKey' => 'term_id'
        ]
    ];

}

そして最後。wp_terms

Term.php

App::uses('AppModel', 'Model');

class Term extends AppModel {

    public $name = 'Term';

    public $primaryKey = 'term_id';

    public $tablePrefix = 'wp_';

    public $displayField = 'name';

    public $hasOne = [
        'TermTaxonomy' => [
            'className' => 'TermTaxonomy',
            'foreignKey' => 'term_taxonomy_id'
        ]
    ];

}

これで設定完了です!お疲れ様です!

動作確認・実際に表示してみる

それでは最後に動作確認をしてみましょう。 たくさんのRelationを使うときはContainableBehaviorが便利なのでAppModelで読み込んでおきましょう。

AppModel.php

App::uses('Model', 'Model');

class AppModel extends Model {

    public $actsAs = ['Containable'];

}

動作確認です。まずは記事からタグを引っ張りだす!

PostsController.php

App::uses('AppController', 'Controller');

class PostsController extends AppController {

    public function index(){
        $articles = ClassRegistry::init('Post')->find('all', 
            ['contain' => [
                'TermRelationship' => [
                    'TermTaxonomy' => [
                        'Term'
                    ]
                ]
            ]
        );
        debug($articles);
    }
}

階層の深い部分にありますがタグが一覧表示されていると思います!

ここまでわかれば簡単!タグから記事を表示しましょう。 PostsController.php

App::uses('AppController', 'Controller');

class PostsController extends AppController {

    public function index(){
        $tags = ClassRegistry::init('Term')->find('all', 
            ['contain' => [
                'TermTaxonomy' => [
                    'TermRelationship' => [
                        'Post'
                    ]
                ]
        );
        debug($tags);
    }
}

最後に

いかがでしたでしょうか。 少し無理やりでしたが、目標は達成出来たかと思います。 CakePHPのリレーションは「_id」がついているものを勝手につなげますが、それを利用したものと言えます。 もっと綺麗に実装出来そうですが、実際に実装していく場合は、findの条件の部分を覆い隠せば綺麗になると思います。

覆い隠す場合は以下の記事が参考になるかもしれません。

findせずにconditionsを返す、DRYなCakePHPのModel実装のススメ

CakePHPerなら持っておかねば!

Webアプリ開発を加速する CakePHP2定番レシピ119
長谷川 智希
秀和システム
売り上げランキング: 34,461
Read more

まだまだあけましておめでとうございます。 年始をいかがお過ごしでしょうか。

私はいつものように、日常と変わらない生活をしています。

さてさて、ユニットテストの件ですが、以前更新して随分時間が経ってしまいましたが、書いていこうかなぁと思います。

今回はバリデーションをテストするための方法を書こうと思います。 前回の routes.php に対するテストの記事は以下になります。 CakePHP2でユニットテスト 〜route.php編〜

バリデーションを適応していく

今回はUserモデルに対してnamenotEmptyを、telに対して独自のバリデーションであるcheckNotEmptynumericOnlyを適応していると仮定します。

User.php

App::uses('AppModel', 'Model');

class User extends AppModel {
    public $validate = [
        'name' => [
            'rule' => ['notEmpty'],
            'message' => '名前を入力して下さい。'
        ],
        'tel1' => [
            'notEmpty' => [
                'rule' => ['checkNotEmpty'],
                'message' => '電話番号を入力して下さい。'
            ],
            'numericOnly' => [
                'rule' => ['numericOnly'],
                'message' => '数字のみ入力して下さい。'
            ]
        ]
    ];

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

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

こういうモデルに対してテストを書いていこうと思います。

バリデーションに対するモデルを書く

テストを書いていきます。

Test/Case/Model/UserTest.php

App::uses('User', 'Model');

class UserTest extends CakeTestCase {

    public function setUp() {
        parent::setUp();
        $this->User = ClassRegistry::init('User');
    }

    public function tearDown() {
        unset($this->User);
        parent::tearDown();
    }

    public function testUserValidations(){
        $baseCase = [
            'name' => '佐藤'
            'tel1' => '090'
            'tel2' => '0088'
            'tel3' => '8800'
        ];

        $testCases = [
            true => [
                ['name' => '谷'],
                ['tel1' => '03', 'tel2' => '1111', 'tel3' => '2222']
            ],
            false => [
                ['name' => ''],
                ['tel1' => ''],
                ['tel2' => -1]
            ]
        ];

        foreach($testCases as $expected => $cases){
            foreach($cases as $case){
                $testCase = array_merge($baseCase, $case);
                $this->User->set($testCase);
                $result = $this->Entry->validates();
                if((boolean)$expected){
                    $this->assertTrue($result);
                } else {
                    $this->assertFalse($result);
                }
            }
        }
    }

}

こんな感じでテストを書いていきます。 このやり方であればテストケースを変更するのも簡単だし、trueとfalseで固まっているのでわかりやすいかと思います。

最後に

いかがでしたでしょうか。

今回もroutes.phpのテストと同じく、直感的でわかりやすかったかと思います。 ユニットテストは自分が安心するのもありますし、機能毎の詳細な仕様書にもなります。 なのでしっかりテストを書いていきましょう。(面倒くさいけど)

CakePHPで新しい本が出てました。読まねば。

Webアプリ開発を加速する CakePHP2定番レシピ119
長谷川 智希
秀和システム
売り上げランキング: 22,052
Read more

みなさんあけましておめでとうございます! 2ヶ月くらい更新してなかったですが、ブログは書き続けてたほうがいいなぁと思っていたので新年からまた書き始めます!

それでは早速書いていきましょう。

最近Composerを使ってCakePHPでFacebookログインを実装したので、そこまでの流れをまとめておこうと思います。

Composerで必要なものをインストールする

composer.jsonから作っていきましょう。

CakePHPFacebook PHP SDKをインストールするので以下のように書けばインストール出来ます。

{
    "name": "facebook-login",
    "repositories": [
        {
            "type": "pear",
            "url": "http://pear.cakephp.org"
        }
    ],
    "require": {
        "pear-cakephp/cakephp": "2.4.4",
        "facebook/php-sdk": "dev-master"
    }
}

composer.pharをダウンロードしてパッケージをインストールしていきます。

$ curl -s http://getcomposer.org/installer | php
$ php composer.phar install

Bakeでプロジェクトを作成します。

$ vendor/bin/cake bake project $PWD --empty

これでブラウザからアクセスすると、いつもの緑画面が出てくると思います。

ここまでで大方終了しましたが忘れちゃいけないので CAKE_CORE_INCLUDE_PATH を書き換えること。

3箇所書き換えていきましょう。

webroot/index.php

define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . APP_DIR . DS . 'vendor' . DS . 'pear-pear.cakephp.org' . DS . 'CakePHP');

webroot/test.php

define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . APP_DIR . DS . 'vendor' . DS . 'pear-pear.cakephp.org' . DS . 'CakePHP');

Console/cake.php

$ds = DIRECTORY_SEPARATOR;
$dispatcher = 'Cake' . $ds . 'Console' . $ds . 'ShellDispatcher.php';

if (function_exists('ini_set')) {
    $root = dirname(dirname(__FILE__));

    // the following line differs from its sibling
    // /app/Console/cake.php
    ini_set('include_path', $root . $ds . 'vendor' . $ds . 'pear-pear.cakephp.org' . $ds . 'CakePHP' . PATH_SEPARATOR . ini_get('include_path'));
}

if (!include $dispatcher) {
    trigger_error('Could not locate CakePHP core files.', E_USER_ERROR);
}
unset($paths, $path, $dispatcher, $root, $ds);

return ShellDispatcher::run($argv);

最後にデータベースをbakeして終了っと!

$ Console/cake bake db_config

実装前の準備をする(Facebookアプリ作成、SDKの読み込み、データベース等)

次にFacebookアプリやFacebookSDKの読み込み、データベースの作成等を行っていきます。

以下のURLに飛び、Facebookアプリを「新規作成」し、アプリIDとシークレットをゲットしておいてください!

次にcomposerでいれたFacebook PHP SDKを読み込んでいきます。 PagesController.php で読み込んでいきましょう。

PagesController.php

<?php App::uses('AppController', 'Controller');
App::import('vendor', 'facebook/php-sdk/src/facebook');

最後にデータベースです。 今回は Admin テーブルを作成しその中にログインに必要な情報を事前に入れておこうと思います。 実際に試す場合は自分のFacebookIDを入れておいてください。

CREATE TABLE IF NOT EXISTS `admin` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `facebook_id` varchar(128) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

INSERT INTO `admin_user` (`id`, `facebook_id`, `created`, `modified`) VALUES
(1, '自分のFacebookID', NOW(), NOW());

最後の最後に! routes.php 内でPagesControllerのルーティングが定められているのでそれをコメントアウトしておきます。

    // Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));

これで終了です。やっと本題にいきましょう!

Facebookログインを実装していく

さて、やっと本題です。 ログインの流れとしては、

  • ログインボタンクリック
  • Facebook側で認証をする
  • 認証後リダイレクト先でFacebookIDが取れ、データベース内にそのIDがあればログインを完了させマイページに飛ばす

こんな感じでやっていこうと思います。

一気にいきます。PagesController.phpにがばっと書いていきます。

PagesController.php

 [
            'authenticate' => [
                'Form' => [
                    'userModel' => 'Admin'
                ]
            ],
            // ログインページ
            'loginAction' => ['controller' => 'pages', 'action' => 'index'],
            // ログイン後リダイレクトページ
            'loginRedirect' => ['controller' => 'pages', 'action' => 'my'],
            // ログアウト後リダイレクト先
            'logoutRedirect' => ['controller' => 'pages', 'action' => 'index'],
            // エラーメッセージ
            'authError' => 'Admin Only'
        ]
    ];

    public function beforeFilter(){
        $this->facebook = new Facebook([
            'appId' => '取得したAppId',
            'secret' => '取得したAppSecret',
            'cookie' => true
        ]);
        $this->Auth->allow('index', 'login');
    }

    protected function _authFacebook(){
        $login_url = $this->facebook->getLoginUrl(['redirect_uri' => Router::fullBaseUrl() . Router::url(['controller'=>'pages', 'action'=>'login'])]);
        return $this->redirect($login_url);
    }

    public function login(){
        $this->autoRender = false;
        $fb_id = $this->facebook->getUser();
        $login_info = ClassRegistry::init('Admin')->find('first', ['conditions' => ['Admin.facebook_id' => $fb_id]]);
        if(isset($login_info)){
            if($this->Auth->login($login_info['Admin'])){
                return $this->redirect(['action' => 'my']);
            } else {
                return $this->redirect(['action' => 'index']);
            }
        } else {
            return $this->redirect(['action' => 'index']);
        }
    }

    public function logout(){
        $this->Auth->logout();
        return $this->redirect(['action' => 'index']);
    }

    public function index(){
        if($this->Auth->loggedIn()){
            return $this->redirect(['action' => 'my']);
        }
        if($this->request->is('post')){
            $this->_authFacebook();
        }
    }

    public function my(){

    }

}

わからなければ質問なり公式ドキュメントを参照してください!!!

Modelのフォルダ内に Admin.php を下記のような感じで作成します。

<?php App::uses('AppModel', 'Model');

class Admin extends AppModel {

    public $useTable = 'admin';

}

Viewは index.ctpmy.ctp を作ります。

index.ctp

Form->create('Admin', ['method' => 'post']);?>

Form->button('Facebookログイン');?>

my.ctp

マイページ

Html->link('ログアウト', ['controller'=>'pages', 'action'=>'logout']);?>

これでFacebookログインが実装できました!!

最後に

いかがでしたでしょうか。 なんとなくの流れは理解出来たかなぁと思います。 何かわからない点がありましたらコメントやTwitterで聞いていただければと思います!

CakePHP本が続々出ていますね。

Webアプリ開発を加速する CakePHP2定番レシピ119
長谷川 智希
秀和システム
売り上げランキング: 15,164
Read more

こんにちは! 最近流行り?のComposerを使ってCakePHPを導入していましたが、色々使いにくいなぁと思っていたのですが、それは僕が使い慣れてないだけだったので、これからCakePHPをComposerで導入しようと思っている人向けにやるべき初期設定を書こうと思います。

それでは始めましょう

composer.jsonの設定

composer.jsonの設定は以下のような感じです。 本当に最低限のインストールしかしない設定になっています。

{
    "name": "test-app",
    "repositories": [
        "type": "pear",
        "url": "http://pear.cakephp.org"
    ],
    "require": {
        "pear-cakephp/cakephp": "2.3.*"
    }
    "config": {
        "vendor-dir": "Vendor/"
    }
}

このあとにcomposer.pharを用いてインストールを行います。 ここらへんは公式ドキュメントが詳しいのでそちらを参照下さい。

編集すべき部分と編集内容

アプリを作成することが出来たら、.htaccessなど、変更する部分はあると思いますが、composerでインストールしたときの編集すべき特有な部分は3つあります。

  • app/webroot/index.php
  • app/webroot/test.php
  • app/Console/cake.php

それぞれのファイルの変更点は以下に書きます。

app/webroot/index.php CAKE_CORE_INCLUDE_PATH部分

define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'Vendor' . DS . 'pear-pear.cakephp.org' . DS . 'CakePHP');

app/webroot/test.php CAKE_CORE_INCLUDE_PATH部分

define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'Vendor' . DS . 'pear-pear.cakephp.org' . DS . 'CakePHP');

app/Console/cake.php

if (function_exists('ini_set')) {
    $root = dirname(dirname(dirname(__FILE__))).$ds.'Vendor'.$ds.'pear-pear.cakephp.org'.$ds.'CakePHP';

    // the following line differs from its sibling
    // /app/Console/cake.php
    ini_set('include_path', $root . PATH_SEPARATOR .  $ds . 〜〜));
}

これを書いてあげることで、どの環境でも設定を変更することなく、動作するようになります。 僕は、ROOT定数を使うという発想がなかったので、各環境においてそれぞれの絶対パスを全て打ち込んでいました。プログラマーとしてまだまだですね。。。

最後に

公式ドキュメントにも同じようなことが書いてありますが、明示的に3つ編集すべきだよ!っていう記事があればさらに便利だなーと思ったのでこんな記事を書いてみました。 僕はまだまだcomposerを使いこなすことが出来ていませんが、もし3つ編集するんじゃなくて、別の方法があるよ!っていうことがあれば教えてくださると助かります!

CakePHPをやるのであればこの本は持っていて損はないです!よく訳に立ってます!

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

みなさんこんにちは。 今回はCakePHP2でユニットテストをする方法を書いていきます。 僕は最近やっとCakePHPを使い始めて1年経過しましたが、多少大きな開発になるとやはりテストを書いたほうが早く開発が出来ますね。

また、やはりなんといってもテストがあるととにかく安心する!←これ大事

開発を進めていくにあたって、安心というものは最高に重要ですね。 僕は普段忙しくても、routeのテスト、モデルのテストは必ず書くようにしています。 最低限ここらへんのテストが正常であれば動くので。

viewとcontrollerは変更が激しいのでなかなか書かないんですけどね。。。

さて、前置きはこれくらいにして、これから何回かにわけて

  • route.phpのテスト
  • Modelのテスト
  • Controllerのテスト
  • Viewのテスト

を書いていきたいと思います。

それでは今回はroute.phpのテストを書いていきます。

適当にroute.phpに記述しよう

まずはCakePHPをインストールしてください。

インストール直後のroute.phpには以下の記述があるだけだと思います。

route.php

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));

これだけでも十分テストを書いていけるのですが、もう1つくらいパターンの違うものを書いておきましょう。 route.phpに以下のコードを追加してください。

Router::connect('/circle', array(
        'controller' => 'pages',
        'action' => 'circle',
        'tag' => 'circle'
    ));

これで準備は出来ました。次はこのroute.phpに対するテストを書いていきましょう。

記述したroute.phpに合わせてテストを書こう

現在route.phpには以下の3つのRouterが設定されていると思います。

route.php

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
Router::connect('/circle', array(
        'controller' => 'pages',
        'action' => 'circle',
        'tag' => 'circle'
    ));

これらのroute.phpに対してテストを書いていきます。 app/Test/Case以下に ‘AppRoutesTest.php’ファイルを作成しファイルに以下の内容を書き込んでください。

AppRoutesTest.php

App::uses('Router', 'Routing');

class AppRoutesTest extends CakeTestCase {

    public function setUp(){
        parent::setUp();
        require APP . 'Config' . DS . 'routes.php';
    }

    public function tearDown(){
        Router::reload();
        parent:tearDown();
    }

    // ここからテスト!!
    public function testTopPage(){
        $expects = array(
            'controller' => 'pages',
            'action' => 'display'
        );
        $url = Router::parse('/');
        $this->assertEqual($expects['controller'], $url['controller']);
        $this->assertEqual($expects['action'], $url['action']);
    }

    public function testPagesAll(){
        $expects = array(
            'controller' => 'pages',
            'action' => 'display',
            'pass' => array(1)
        );
        $url = Router::parse('/pages/1');
        $this->assertEqual($expects['controller'], $url['controller']);
        $this->assertEqual($expects['action'], $url['action']);
        $this->assertEqual($expects['pass'], $url['pass']);
    }

    public function testCirclePage(){
        $expects = array(
            'controller' => 'pages',
            'action' => 'circle',
            'tag' => 'circle'
        );
        $url = Router::parse('/circle');
        $this->assertEqual($expects['controller'], $url['controller']);
        $this->assertEqual($expects['action'], $url['action']);
        $this->assertEqual($expects['tag'], $url['tag']);
    }
}

これでテストを書くことが出来ました! コードの中身の説明ですが・・・

setUp()はテストが行われる前に実行される関数、tearDown()はテストが完了したあとに実行される関数です。 またそれぞれのテストケースですが、まず最初に$expects変数の中に、正しくルーティングが設定してあれば返ってくるであろう配列を書いておきます。 そしてRouter::parse()でURLをパースします。パースすることによって、route.phpに書いてあるルーティングに従って、CakePHPがcontrollerやactionを割り当てます。 その結果が$urlに入っているので、あとはPHPUnitのassertEqual()で正しいかどうかを調べています。

3番目のテストケース「testCirclePage」のときのように、少し特殊なルーティングを行っている場合、以下のようにすればどのような値が$urlにわたっているか調べることが出来ます。

$url = Router::parse('/circle');
debug($url);

こうやって調べてテストを書くことによって、どんなルーティングにも対応出来ているテストケースを書くことが出来ます!

テストを動かそう

それでは最後にテストを動かしましょう。 インストールしたディレクトリの最後に「test.php」と打てばGUIでテストを実行出来るページが表示されます。 こんな感じで↓

AppRoutesをクリックし、全てがグリーンであればテストは全て成功しています! こんな感じで↓

また、先ほどのRouter::parse()の中身を見る方法は、この画面の赤い枠で囲まれた部分をクリックするとdebug結果を見ることが出来ます 赤枠をクリック!

debug結果が表示される

これでroute.phpのテストはなんでも書けるはず!!

最後に

いかがでしたでしょうか。 route.phpに対するテストは、CakePHPのテストの中でも1番簡単なので、これをまずは理解しましょう。 もし何かわからないことがあれば、@DAI199までリプライください!

テストに関しては以下の本が1番詳しく書いてあると思いました。

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

こんにちは。 Google スプレッドシートに書込が出来て喜んでいるたがみです。

早速ですが、Googleスプレッドシートに書き込みが出来ることを知っていますか? これ出来ると便利なんですよねー。 フォームから入力されたデータを見る人はプログラムわからない人だったり、データベース触れない人だったりするんですが、ExcelベースのGoogleスプレッドシートだと見た目Excelなんで抵抗なく、触ることが出来ます。

ということで簡単なPHPのクラスを作ったので紹介します。

ただまとめただけではありますが、簡単にスプレッドシートに書込が出来ます!

Githubにアップロードしているのでダウンロードしてください。 GgSpread – github

それでは簡単なサンプルを作成してみましょう。

1, Zendフレームワークをインストールする

ダウンロードしてきたGgSpreadを使用するためには、Zendフレームワークのコンポーネントである、Gdataというライブラリが必要なので、Zendフレームワークをインストールします。 インストールといっても、中身はただのPHPファイルなので、PHPが動く環境であればどこでもインストールすることが出来ると思います。

Zendフレームワーク ダウンロード

2, Googleスプレッドシートを作成する

テスト用のGoogleスプレッドシートを作成しましょう。 スプレッドシートを作成したら、以下の画像のように、1行目に項目を入れておきましょう。 これがないと動作しません。

※注意! 項目が日本語の場合書き込み出来ないぽいです。英数字で指定するようにしましょう!

3, GgSpreadをインクルードする

適当なPHPファイルを作成して、GgSpreadをインストールしましょう。 当たり前ではありますが、以下のコードで動作します。

require_once 'GgSpread.php';

4, インスタンスを作成する

それではGgSpreadのインスタンスを作成しましょう。 引数としては、2でスプレッドシートを作成したアカウントのメールアドレス、パスワード、スプレッドシート名、ワークシート名です。 以下例になります。

$ggspread = new GgSpread("メールアドレス", "パスワード", "テストシート", "シート1");

5, 書き込みたいデータをsetする

書き込みをしたいデータを連想配列でsetします。 以下が例になります。

$output = array(
    'col1' => 'test',
    'col2' => 'test2',
    'col3' => 'test3',
    'col4' => 'test4',
    'col5' => 'test5'
);
$ggspread->set($output);

6, 書き込む!!

データをセット出来ればあとは書き込むだけです! 以下例です。

$ggspread->insert();

これで書き込み完了です!!

終わりに

いかがでしたでしょうか。 GgSpreadを使えば簡単にGoogleスプレッドシートに書き込みをすることが出来ます。 今後の課題としては、GgSpreadで、スプレッドシートのデータを読み込み出来るようにすることです。 近々やることがあれば、また共有したいと思います。

何か質問等ございましたら、以下のFacebookコメント欄、またはTwitter(DAI199)でリプライください。

Read more

PHPって本当に色々な関数がありますね。 今回は僕が知らなかった、PHPの関数を紹介します!

HTMLの中にはたくさんの情報を詰め込むことが出来ます。 最近ではHTML5のData APIなどを使えばタグごとに色々な情報を埋め込むことが出来ますよね。

PHPを使えば簡単に、あるタグに関する情報を取ってくることが出来ます。

それは「meta」タグです! metaタグって普段は機械的にしか使わないですよね。 ただPHPのある関数を使えばmetaタグに情報を埋め込むことが出来るんです!

その関数とは、「get_meta_tags」です!

get_meta_tags ・・・ ファイル上のすべてのメタタグ情報を配列に展開する

使い方

例えばHTMLに以下のようなものが書いてあったとします。

あるHTML



 

これを以下のPHPで読み込んでみます。

あるPHP

 "testですよ"
echo $tags['words']; // => "ここには重要なワードがごにょごにょ" 

またこの関数は

でパースを終了するので、思いっきりhtml内のヘッド要素に書いてあるものを抜き出す関数なのですね。

本当にPHPには色々な関数があります。 何かマイナーな関数を知っている人がいればぜひ教えてください!!

Read more

PHP AdventCalender2012 5日目担当のたがみ(@DAI199)です。

4日目担当の@mawatarinさんの記事、とても丁寧で参考になります! あんな丁寧な記事が書けるように日々努力しようと思いました。

@mawatarinさんの記事はこちら

僕自身CakePHPをよく使っていて、アプリもCakeで作っているため、検索を実装するときは参考にしたいと思います!

さて、今まで書いた方々のレベルが高くて、こんな内容でいいのかと申し訳ない気持ちになりますが、せっかくのお祭りのようなものなので、普段なかなかしないことをしてみようと思います。

今回はオレオレRSS(私が読んだ記事をひたすら更新するRSS)を作成してそれをGoogleReaderなりで読み込んでみたいと思います。

なぜいまさらRSS?

なぜいまさら私がRSSをやろうと思ったのかというと、約8ヶ月前くらいまで私の主な情報源はTwitter、Facebookでした。 当時はTwitterのタイムラインを全て追い、僕が当時フォローしていた約300人のつぶやきを全て拾っていました。 そのためとても情報通でしたが、その分時間を使いました。

時間をあまり使わず、情報収集する効率のよい方法はないか。

そんなときに目をつけたのがRSSでした。 今では情報収集の6割程度はRSSで行い、それを補完する形でTwitterやFacebookを使うようになりました。 それだけ僕の中ではRSSというのは衝撃なものでした。

ただよく考えてみると、RSSがXMLなのはわかってるけど作ってみたことないな・・・と感じていたため、今回この機会に勉強させていただいて、その方法を共有しようと思いました。 これが僕が今回RSSを題材に選んだ理由です。

とりあえずRSSを出力してみる

それでは、ある程度簡単なのはわかっているのですが、RSSを実際に出力してみましょう!

&lt;?php
// ヘッダーを出力する
header(&quot;Content-type: text/xml;charset=utf-8&quot;);
echo '&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;';

// サイトの情報を書き込む
echo '
&lt;rss version=&quot;2.0&quot;&gt;
&lt;channel&gt;
&lt;title&gt;tagamidaiki.com のオレオレRSS&lt;/title&gt;
&lt;link&gt;https://tagamidaiki.com&lt;/link&gt;
&lt;description&gt;FacebookのGraphAPIやCakePHP,JavaScriptなどの記事を更新していきます。&lt;/description&gt;
&lt;category&gt;php, graph api, facebook, cakephp&lt;/category&gt;
&lt;generator&gt;@DAI199&lt;/generator&gt;
&lt;webMaster&gt;@DAI199&lt;/webMaster&gt;
';

// 記事の内容を更新
for(ループさせる)
{
echo '
&lt;item&gt;
&lt;title&gt;Test'.$i.'&lt;/title&gt;
&lt;link&gt;https://tagamidaiki.com&lt;/link&gt;
&lt;description&gt;TestTest&lt;/description&gt;
&lt;author&gt;@DAI199&lt;/author&gt;
&lt;category&gt;php&lt;/category&gt;
&lt;/item&gt;
';
}

echo '
&lt;/channel&gt;
&lt;/rss&gt;
';
?&gt;

( ゚д゚) 思ったより4倍くらい簡単だった。。 よく考えてみなくてもただタグ組み立てるだけですもんね。。。

それをGoogleReaderで読み込んでみる

それでは本当にこれを読み込んでくれるのか。 GoogleReaderで読み込んでみました。

おお!すごい!ちゃんと読み込んだ! 小さな感動を味わいました。よかったです。

今回の記事で本当にやりたかったことは?

今回の記事で本当にやりたかったことを書いてこの記事を終わろうと思います。

本当はFacebookログインして、そこには自分の読んだ記事を追加するフォームがあって、そこに情報を打ち込むとその人のRSSが作成される、みたいなことがしたかったです。 用はTwitterやFacebookでキュレーションしている情報たちをRSSに集めてそれらを一覧にすることでキュレーションプラットフォームみたいなものを作りたかったのです。 これ、結構いけると思うのですがどうでしょうか。 時間があるときになんとか作ってみたいアプリの1つです。

終わりに

ほとんどPHPのこと、関係なくて申し訳ありません。 RSSどうやって作成してるんだろう?って思ってる僕みたいな人のためになれれば幸いです! いつかリベンジで上記のアプリを作ってみたいです。

それでは明日のAdventCalenderも楽しみです! 次の方、よろしくお願いします!!

CakePHP AdventCalender2012 1日目に参加しました!

Read more