読者です 読者をやめる 読者になる 読者になる

データ検索をマスターする! (4/6) 補足

 
 
//find()にQueryExpressionを使うサンプル
public function find() {

//絞り込んだ結果のエンティティ配列
$persons = [];

//リクエストの種別がPOSTであるなら
if ($this->request->is('post')) {
//添字の'find'とは、テンプレートの該当フォームのname属性に指定したもの
//テキストフォームの例: $this->Form->text( 'text1'←ここ )
//なお、data['find']やdata('find')はdeprecated
//getData('find')が現行バージョンでの推奨らしい
$find = $this->request->data['find'];
//最初にSELECT * FROM persons のクエリを作成する
//なお、条件を付加していく段階ではクエリは実行されない
//データが必要になった時、つまりテンプレートでのforeachで初めて実行される
//find('all')や、find()->all()などの場合はすぐに実行される
$query = $this->Persons->find();
//上のクエリに適合したクエリエクスプレッションを生成
$exp = $query->newExpr();
//絞込に使用するための無名関数を宣言
//第一引数にはクエリエクスプレッション、
//第二引数には、今回は名前が絞込の条件となるので、
//"まつもとゆきひろ, やくみつる"といったコンマ区切りの文字列を代入する
$fnc = function($exp, $f) {
return $exp
//名前がNULLでない
->isNotNull('name')
//メールアドレスがNULLでない
->isNotNull('mail')
//年齢が0より大きい
->gt('age',0)
//名前が第二引数で渡されたどれかに該当する
//なお、explode関数はコンマ区切りだった文字列を配列に変換している
->in('name', explode(',',$f));
};
//無名関数をwhere句に設定する
$persons = $query->where($fnc($exp,$find));
}
//クエリをテンプレートに渡すためにset()する
$this->set('persons', $persons);
$this->set('msg', null);
}

複数のテーブルのJOINした結果を表示

クエリビルダにおいて、innerJoinWith()やleftJoiinWith()でJOINしたものをテンプレートで表示するためには

$tenancy->_matchingData['Tenants']->stage

stackoverflow.com

のように書きます。

もし不安な場合はdebugメソッドもしくは$tenancyのみで出力し確認します。

 

クエリビルダのcontain()で結合した場合は

$tenancy->tenant->stage

です。

グローバルにインストールしたcomposer.pharの場所

C:\ProgramData\ComposerSetup\bin内にある。

もしここにもない場合はEverything等のファイル検索ソフトを使う。

#1071 - 索引のキーが長すぎます。最大 767 バイトまでです。と出たとき

 

CREATE TABLE tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    created DATETIME,
    modified DATETIME,
    UNIQUE KEY (title)
);

このtitle属性は255文字までを格納する。
同じ文のタグを重複して登録することは許されないため、ユニークキーとして扱いたい。

しかし、例えば文字コードにutfmb4を設定しているとき、utfmb4は各文字4バイトで表現するので総バイト数は 4 * 255 = 1020Bとなり、 767バイトをゆうに超えてしまう。

解決策としては 各文字にかかるバイト数 * 最大文字数 < 767 となるようにSQLを変更する。

上記の場合では191文字が限界。そのため3行目が

title VARCHAR(191)

となる。

Unknown finder method とは

$bookmarks = $this->Bookmarks->find('tagged', [

テーブルのfindメソッドの第一引数が重要。

 

たとえば上記のようにBookmarks->find('tagged',のようになっているときは、
BookmarksTableクラスのfindTaggedメソッドを探しに行く。

ここで見つからないときUnknown finder method ("tagged")とエラーが出る。

見つかった時はfindTagged()に第二引数であるオプションを渡して結果をもらう。

 

ここから補足。

 

今回は、指定したタグが付いているブックマークの一覧を表示するためにタグ付きのブックマークを絞り込みたい。
そのためにはControllerはTableクラスに依頼し、絞り込んだ結果を返して貰いたい。

// タグ付きのブックマークを探すために BookmarksTable を使用
$bookmarks = $this->Bookmarks->find('tagged', [

'tags' => $tags
]);

これは、BookmarksControllerがBookmarksTableに依頼する。なぜならTableがDBとの通信を担当するから。
findTaggedメソッドに指定したタグを渡すことでBookmarksTableはブックマークを絞りこめるようになる。

 

さて、次はTableクラスの処理。

public function findTagged(Query $query, array $options)
{

まずここは、呼び出したクエリインスタンスと先程の第二引数(compact('tags'))が渡されることを意味する。

 

$bookmarks = $this->find()->select(['id', 'url', 'title', 'description']);

表示したい項目一覧を設定する。SELECT ID,URL, ...のような感じ

 

if (empty($options['tags'])) {

第二引数に何も渡されていなかったとき=タグが何も指定されていない時


$bookmarks->leftJoinWith('Tags')->where(['Tags.title IS' => null]);
タグがNULLの行を検索

 

} else {
$bookmarks->innerJoinWith('Tags')->where(['Tags.title IN ' => $options['tags']]);

指定したタグのどれかに合致する行を検索
}

return $bookmarks->group(['Bookmarks.id']);

IDでGROUP BYしたものを返却

 

}

protected function _setPassword($value)とは

結論はこれ。

[CakePHP3] Setter(セッター)とGetter(ゲッター)をざっくりと知る。 – gomokulog

以下補足。

C#にはプロパティという機能がある。
プロパティを実装すると、メンバ変数 x を持つクラスAがあるとき、a.x としても自動的にgetX()が呼び出されるというもの。つまりゲッタがメンバ変数としてふるまう。

これと似たようなノリでCakePHPでは、エンティティに値をセットするとき、
エンティティに_set{$変数名}というメソッドを作っていれば、自動でセッタが呼び出されるそうだ。

 

具体的には$entity->変数名 = 値; などを実行した時に_set{$変数名}というメソッドを探し、存在したら実行する。

逆に値をgetする時(テンプレート内など)は_get{$変数名}が探され呼び出されるらしい。

bin/cake bakeがWindowsでうまくいかないわけ

bin/cake bake all users
bin/cake bake all bookmarks
bin/cake bake all tags

CakePHP3のbookmarkerチュートリアルにて遭遇。

Linuxとは違ってWindowsでは区切り文字を\にする必要がある。

つまり、Windowsでの正解は

bin\cake bake all users
bin\cake bake all bookmarks
bin\cake bake all tags