CakePHP

みなさんこんにちは!

最近はRailsとSwiftで四苦八苦してるたがみです! 久しぶりにCakePHPを触る機会があり、忘れちゃいけないのでブログに残しとこう!と思った次第です。

今回の例は、 あるプロジェクトでcomposerを使ってプラグイン等を管理しているが、過去のプラグインでPackagistに登録されていない。どうやれば解決出来るんだっけ? です!

それではいってみましょう!

Composerでzipを扱う

今回インストールしたかったプラグインはACLをGUIで簡単に確認することが出来るプラグイン「Plugin ACL」です。 とても便利なのですが、DLしてプラグインの中身を見る限り、Packagistに登録されていない?

※9/27 12:30 追記 Packagistに登録されていました!僕の確認ミスです!ただ有志の方が非公式で登録されているようです。 alaxos/acl – Packagist

DLするURLはこちらですが、これをComposerでインストール出来るようにしたいと思います!

ComposerではPackagistに登録されているものも扱えますし、zipでまとめられているプラグインのURLを用いてインストールすることも出来ます。 なので今回は先ほどDLしたURLからインストール出来るようにします。

composer.jsonに以下のように書けばインストール出来ます!

composer.json

{
  "repositories": {
    {
      "type": "package",
      "package": {
        "name": "alaxos/plugin_acl",
        "version": "2.3.0",
        "dist": {
          "url": "http://www.alaxos.org/download/alaxos_acl_2.3.0.zip",
          "type": "zip"
        }
      }
    }
  },
  "require": {
    "alaxos/plugin_acl": "2.3.0"
  }
}

ハイライトしてある6行目の名前をrequireの中の16行目で使用することが出来るんですね! 知ってしまえば簡単なんですが、こういうのって探さないと書けないですよね・・・

皆様の役に立てれば!

最近出たCakePHPでのCIの方法を書いた本 一回目を通さないとなー ちなみに個人的にはCircleCIおすすめです!!

CakePHPで学ぶ継続的インテグレーション
渡辺 一宏 吉羽 龍太郎 岸田 健一郎 穴澤 康裕
インプレス
売り上げランキング: 3,318
Read more

タイトルとおりのことです。

うまくjoin出来てるはずなのにな〜〜なんでだろうなぁ、sql_dumpでちゃんと思い通りのSQL発行されてるのにな〜なんだろうなぁ・・・と思い、色々optionを指定していたらタイトルとおりのことが出来ていなかったせいで結果が反映されていませんでした。

下記のようなコードを書いた場合はちゃんとfieldsも指定しましょう

$this->User->find('all', [
    'joins' => [
        'comment' => [
            'table' => 'comment',
            'alias' => 'Comment',
            'type' => 'inner',
            'conditions' => [
                'User.id = Comment.user_id'
            ]
        ]
    ],
    'fields' => '*'
]);

これで解決。めでたしめでたし!

参考:http://stackoverflow.com/questions/4354846/cakephp-display-custom-fields-from-array/4355357#4355357

cakePHP2.0のfindでINNER JOINしてもJOINしたテーブルが表示されない

詳解CakePHP辞典―2.0/2.1/2.2/2.3対応
滝下 真玄
秀和システム
売り上げランキング: 91,713
Read more

みなさんこんにちは!

昨日更新した記事が、僕自身の勉強にもなってるなぁと感じたので調子にのって楽しそうなコアライブラリを探しました! 今日書くのはInflectorクラスです。

Inflectorクラスとは

文字列を単数形や複数形にしてくれたりキャメルケースやアンダースコアケースにしてくれたりする知っておくと超ベンリなクラスです。

使うには使いたいクラスで以下のコードを使いたいクラスで書いておきましょう。

App::uses('Inflector', 'Utility');

これで読み込み完了!!

それでは簡単に紹介してみます。 詳しい部分は公式Cookbookを参考すると素晴らしいと思います。

Inflector::pluralize($singular)

単数形のものを複数形にしてくれます。何気に便利かも

$string = "apple"; // 'man', 'person'
$result = Inflector::pluralize($string);
// 結果
// => 'apples' 'men', 'people'

Inflector::singularize($plural)

これは逆に単数形にしてくれるもの!

$string = "apples"; // 'men', 'people'
$result = Inflector::pluralize($string);
// 結果
// => 'apple' 'men', 'person'

Inflector::underscore($camelCase)

キャメルケースをアンダースコアに変換してくれる関数

$string = "TestCase";
$result = Inflector::underscore($string);
// 結果
// => "test_case"

Inflector::camelize($underscored)

これは逆にアンダースコアをキャメルケースにしてくれる関数

$string = "test_case";
$result = Inflector::camelize($string);
// 結果
// => "TestCase"

最後に

これら以外にも文字列をテーブルの命名規則に従ったものに変換してくれる関数Inflector::tableize、クラスの命名規則に従ったものに変換してくれる関数Inflector::classifyなど色々面白いものがたくさんあるので暇なときにでもCookbookを見てみると色々面白いものが見つかるかもしれません!

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

CakePHP2を使い始めて約2年が経ちましたが最近やっとコアライブラリまで目がいくようになりました(遅い) CakePHPにはコアライブラリとしてたくさんの便利な関数がつまっています。 これらを知っているだけでも開発が相当便利になるなぁと最近感じているのでその中から今回は「String」ライブラリの中から便利だなぁと思う関数を紹介したいと思います。

Stringライブラリの使い方

使いたいクラス内で以下のコードを挿入すればあとはスタティックに使うことが出来ます。

App::use('String', 'Utility');

String::tokenize($data, ":");

String::tokenize($data, $separator = ‘,’, $leftBound = ‘(‘, $rightBound = ‘)’)

$separatorで$dataをトークン化します。$leftBountと$rightBoundの間にある$separatorは無視されるので結構便利です。 データをある定型化しておいてそれを分割するようなときに便利です。

$data = "Tagami:Daiki:DAI199";
$result = String::tokenize($data, ':');
debug($result);
// 結果
// => array('Tagami', 'Daiki', 'DAI199');

String::insert($string, $data, $options = array())

文字列内にシンボルのような形でキーの値を書いておいて、それに対応する$dataの値を入れてくれる関数です。 シンボルの形は$optionsで変更可能です。 ドキュメントは以下です。 class String::insert()

$string = ":name is :age years old.";
$result = String::insert($string, ['name'=>'tagami', 'age'=>23]);
// 結果
// => "tagami is 23 years old."

$string = "*name* is *age* years old.";
$result = String::insert($string, ['name'=>'tagami', 'age'=>23], ['before'=>'*', 'after'=>'*']);
// 結果
// => "tagami is 23 years old."

String::highlight($haystack, $needle, $options = array())

$haystackの文字列の中から$needleに当てはまる文字列を$options[‘format’]で指定した文字列でハイライト表示します。 オプションとしては以下があります。

  • format・・・文字列。ハイライト表示に使うHTMLを指定する
  • html・・・真偽値。trueの場合はHTMLタグを無視してテキスト部分のみハイライト表示する
$string = "これはテストです。テスト出来るかな?";
$result = String::highlight($string, 'テスト', ['format'=>'\1']);
// 結果
// => "これはテストです。テスト出来るかな?"

String::toList(array $list, $and = ‘and’)

最後にちょっと面白い関数があったので紹介します。 $listの文字列を結合して、最後の結合箇所で利用する文字列を指定出来ます。 ちょっと何言ってるかわからないと思うので以下の例を見てみてください。わかるはずです。

$colors = ['red', 'orange', 'yellow', 'blue'];
$result = String::toList($colors);
// 結果
// => "red, orange, yellow and blue"

上のような感じで使います。’and’の部分は変更可能なので以下のようにも使えますね。

$lang = ['日本語', '英語', 'ドイツ語'];
$result = String::toList($lang, 'そして');
// 結果
// => "日本語, 英語 そして ドイツ語"

最後に

意外と知っているだけで自分で実装しなくていいので便利ですよね。 たまにドキュメントをだらだら読むのでまた何かいいものが見つかれば書いていきたいなぁと思います。

今回紹介したもののドキュメントは以下になります。

コアライブラリ – String

これ買いました

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

こんにちは!

今日はCakePHP2のプラグインである「Upload」プラグインで画像をあげなおす処理を書いてみます。 結果的に無理矢理感が出てしまってますが、とりあえず実装は出来るってことでw 綺麗に書きたい〜〜

Uploadプラグインが動くまで設定

以前Uploadプラグインの記事を書いたのでこれの途中までやってみてください。

CakePHP2で画像アップロードプラグインである「Upload」を試してみた

コードを書く

それでは早速書いていきます。 まずはControllerから

UserController.php

request->is(['post', 'put'])){
            if($this->User->createWithImage($this->request->data)){
                $this->Session->setFlash(__('編集'));
                return $this->redirect(['controller'=>'user', 'action'=>'index']);
            }
        }

        if(!$this->request->data){
            $this->request->data = $this->User->find('first');
        }
    }
}

そしてModel

User.php

 [
            'image'
        ]
    ];

    public function createWithImage($data){
        if(!empty($data[$this->alias]['image']['name']) && !empty($data[$this->alias]['id'])){
            $data[$this->alias]['image']['remove'] = true;
        }

        $this->create();
        if($this->saveAll($data)){

            // removeフラグを消して画像を保存する
            if(isset($data[$this->alias]['image']['remove'])){
                unset($data[$this->alias]['image']['remove']);
            }

            if($this->saveAll($data)){
                return true;
            }
        }
    }

}

最後にView View/User/index.ctp

Form->create('User', ['type'=>'file']);
echo $this->Form->input('image', ['type'=>'file']);
if(isset($this->data['User']['image'])){
    echo $this->Html->image('../file/user/'.$this->data['User']['id'].'/'.$this->data['User']['image']);
}

echo $this->Form->hidden('id');
?>

一番大切な部分はModelのとこの

$data[$this->alias]['image']['remove'] = true;

です。これを指定して保存するとテキストデータ等は保存されますが、画像データは消去されます。

このことに関するドキュメントはこちら Remove a current file without deleting the entire record

一度消去したあとに remove フィールドを消して保存しなおすことで画像アップロードをもう一度行って画像の入れ替えを行いました。

ごりごりですけど一応わかりやすいかなぁと思います!

最後に

お疲れ様でした! やっぱりプラグインを使ってアップロード処理を外にまかせているととても楽ですね。 remove フラグがあるおかげで色々なことが柔軟に出来る気がします。 参考になれば!!

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

こんにちは!

CakePHPでアプリ作ってるときにあるURLをwww付きに固定したいなぁって思うとき、ありますよね! そんなときに簡単に出来る方法があるのでご紹介します。

.htaccessに書き込む

コードで行うことも可能だと思うのですが今回私が行った方法は.htaccessに付け加える方法です。 もしコードでこうやれば出来るよ!ってのがあればぜひぜひ知りたいので教えてほしいです!

以下のコードをトップディレクトリに置いてある.htaccessに追記して下さい。 全体としては以下のようになります。


   RewriteEngine on
   RewriteCond %{HTTP_HOST} !^www\. [NC] 
   RewriteRule ^(.*)$ "http\:\/\/www.%{HTTP_HOST}/$1" [R=301,L]
   RewriteRule    ^$ app/webroot/    [L]
   RewriteRule    (.*) app/webroot/$1 [L]

もうこれだけ!なんて簡単!!

ただ一応注意しておくと・・・ この方法だとどんな方法でも無理やりwwwがついちゃいます。 なのでlocalhostとかで開発してるときもwww.localhostみたいな感じになっちゃってうざいです。

とりあえず本番環境にだけ適応させるにはこの方法でいいかぁとも思うのですが、やっぱりコード管理が一番安定するかな、とも思ってます。

今後試行錯誤してwwwに統一するコードが出来たらまた紹介させていただきますね!

誰かwwwに統一するときこのコード使ってるよ!ってのがあったら重ね重ねですが教えてくださいw @DAI199までお願いします!!

CakePHPやってるならとりあえず持っておけ本!

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

Q. CakePHP2でリレーション先までデータを保存したい
A. saveAllメソッドにdeepオプションを渡してあげましょう。 例 ・ArticleがItemを複数持ち、ItemはMetaItemを複数持っている(Naverまとめ的な) Article.php
 array(
            'className' => 'Item',
            'foreignKey' => 'article_id',
            'dependent' => true
            )
    );
}
Item.php
 array(
            'className' => 'MetaItem',
            'foreignKey' => 'item_id',
            'dependent' => true
        )
    );
}
MetaItem.php
 array(
            'className' => 'Item',
            'foreignKey' => 'item_id'
        )
    );
}
保存するデータの構造
array(
    'Article' => array(
        ...
    ),
    'Item' => array(
        (int)0 => array(
            ...
        ),
        (int)1 => array(
            ...
            'MetaItem' => array(
                (int)0 => array(
                    ...
                ),
                (int)1 => array(
                    ...
                )
            )
        )
    )
)
使うメソッド
$this->Article->saveAll($data, array('deep' => true));
・コメント なぜかリレーションが1段階先しか保存してくれない!!って困ったのでぐぐってみるとdeepオプションというのがあるじゃないですか! ということで早速使ってみると見事解決。よかったよかった〜〜 適切なデータ構造を作って渡してあげれば適当に処理してくれるCakePHPありがとうございます!!
詳解CakePHP辞典―2.0/2.1/2.2/2.3対応
滝下 真玄
秀和システム
売り上げランキング: 112,599
Read more

こんにちは!

ModelのhasManyを使って、データをfindしてきたとき、FormHelperでViewにどう表示させるもんか悩んだのでメモ変わりに書いておきます。 多分なんのこっちゃ言ってるかわからないと思うのですが、以下のようなデータがあった場合にFormHelperのデフォルト値に反映させて、まぁいわば編集のような機能をつけたいときに悩んだのです(ようわからん)

array(
    'Article' => array(
        'id' => '1',
        ....
    ),
    'Item' => array(
        (int)0 => array(
            'id' => 1,
            'order' => 1,
            ....
        ),
        (int)1 => array(
            ....
        )
    )
)

こんなデータがあったとします。このデータをControllerからViewに渡していると仮定しときます($this->dataにぶちこむ) これをFormHelperでぱぱっと表示出来る方法はないかと色々探していたら以下のようなものを見つけました。

How to edit form with hasMany (multiple rows)

ようは以下のような感じです。

data['Item'] as $item){
    echo $this->Form->hidden('Item.' . $count . '.id');
    echo $this->Form->hidden('Item.' . $count . '.order');
    // 必要に応じて増やす
    $count++;
}

// Output
// 
// 
// ...
// 

このようにコードを書けばあるArticleに紐づくhasManyなものをまとめて編集したい!のような要望にも答えられるかと思います。 ただ$countがちょっとださいなぁと。 あともう1階層深いリレーションを表示させようとするとイテレートをもう1段階増やさなければならないのでカウンターも増えてしまうのが嫌だなぁと。

もっとうまい方法があるはずなんですが、もし誰かこうやったほうがよくない?みたいなのがあれば教えてください!!

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

みなさんこんにちは!

リレーションを組んでリレーション先も同時に消す方法を勘違いしていたので自分の戒めのためにメモとして残しておきます。

データを消すときはdeleteメソッドを使ってcascadeをtrueにすればリレーション先も消してくれると思っていました。 ただドキュメントよく見ると、この値、defaultではtrueなんですよね・・・

これではうまく消えない・・・ではどうすればいいのかというとリレーションを組んでいる部分でdependentオプションをtrueにしておかなければならないのです(´・ω・`) つまり2箇所をしっかりtrueにしておけばリレーション先もうまく消えてくれる、ということです。

これだけではブログ記事としてはなんだかなぁなので一応確認しておきます。

データベース、コードの確認

CakePHPは前まとめたもので作ってあることを前提とします。 試してみたい方は以下の記事でプロジェクトを作る部分までやっておいてください。

CakePHP2をComposerでインストールしてプロジェクトを立ち上げるまで

そしてデータベースは以下のようなものを準備します。適当なので気にしないでください。

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE IF NOT EXISTS `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO `users` (`id`, `name`, `created`, `modified`) VALUES (1, 'test1', NOW(), NOW());
INSERT INTO `items` (`id`, `user_id`, `name`, `created`, `modified`) VALUES (1, 1, 'test2', NOW(), NOW());

User.phpはこんな感じ

Model/User.php

 [
            'className' => 'Item',
            'foreignKey' => 'user_id',
            'dependent' => true,
        ]
    ];
}

Controller/UsersController.php

set('users', $this->User->find('all'));
    }

    public function delete($id = 0){
        if($this->request->is('get')){
            throw new MethodNotAllowedException();
        }
        if($this->Article->delete($id, true)){
            $this->Session->setFlash(__('%s番の記事を削除しました', h($id)));
            return $this->redirect(['controller'=>'users', 'action'=>'index']);
        }
    }
}

最後にView

View/Users/index.ctp


これで/users/にアクセスして削除をおしてみてください。 その後データベースを確認してうまく消えていますか?

User.phpの10行目をコメントアウトしてデータを入れなおしてもう一度消してみてください。 今度はリレーション先が消えていませんよね?それで僕は少しはまりましたw

最後に

CRUDというCakePHPのプラグインがあるのですが、その中身でdeleteメソッドの部分にcascadeを指定する場所がなかったので。あれ?これおかしいのかな?とか思ってた自分が一番おかしかったです(´・ω・`)

何事も常に見なおしてしっかり確認していかないとダメですね。

僕のようなことを繰り返さないためにも

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

CakePHP2の画像アップロードプラグイン「UploadPack」を試してみた

こんにちは! CakePHP2の画像プラグインを色々試しているので今回は「UploadPack」というのを試してみました。 いってみましょう!!

CakePHP2とUploadPackをインストール、有効化

インストールからしましょう。 Composerでインストールしたいのですが「UploadPack」はCompserに対応していないため、git submodule などでインストールするといいかもしれません。

composer.json

{
    "name": "uploadpack-example",
    "repositories": [
    {
        "type": "pear",
        "url": "http://pear.cakephp.org"
    }
    ],
    "require": {
        "pear-cakephp/cakephp": "2.4.*",
        "cakephp/debug_kit": "2.2.*"
    }
}

とりあえずCakePHPが動くように設定していきましょう。 以前まとめたのでこちらをご覧下さい。

CakePHP2をComposerでインストールしてプロジェクトを立ち上げるまで

プロジェクトが立ち上がったらgit submoduleでインストールしましょう。

$ git submodule add https://github.com/szajbus/uploadpack.git Plugin/UploadPack

最後にbootstrap.phpにプラグインを読み込むように書き込みましょう。

Config/bootstrap.php

CakePlugin::load('UploadPack');

これで有効化出来ました。

UploadPackの設定

実際にコードを書いていきます。

UploadPackでは_file_nameというものがついているフィールドに画像情報を保存するのでテーブル内に_file_nameがついたフィールドを用意しましょう。

CREATE table users (
    id int(10) unsigned NOT NULL auto_increment,
    login varchar(20) NOT NULL,
    avatar_file_name varchar(255)
);

Userモデルに対してコードを書いていきます。

Model/User.php

 [
            'avatar' => [
                'styles' => [
            'thumb' => '80x80'
        ]
            ]
        ]
    ];
}

アップロード処理をControllerに書いていきます。といってもデータを普通に保存するような形で構いません。

Controller/UsersController.php

request->is('post'){
            $this->User->create($this->request->data);
            if($this->User->save()){
                $this->Session->setFlash('image upload!');
            }
        }
    }
}

あとはViewです。「UploadPack」にはhelperがついているのでそこから呼び出しましょう。(Controllerでhelperを読み込んでます。6行目)

View/Users/index.ctp

Upload->uploadImage($user, 'User.avatar', array('style' => 'thumb')) ?>

これで動きますー! 80×80の画像が生成されたと思います。

最後に

データベースのフィールドに制約があるものの、ヘルパーもついていてとても簡単に画像アップロードが実装出来るのでおすすめのプラグインです。 composerに対応してくれるともっと嬉しいなーってプルリク送れってことですねすみません!

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