いろいろ備忘録

雑記です。

CakePHP3のテーブルとエンティティの違い

CakePHPMVCであり、その内のモデルを2種類に分けたものがテーブルとエンティティです。
ざっくり言うとテーブルとはそのままDBのテーブル(集合)を表し、エンティティとは各行を表します。

テーブルクラスにはDBとの通信に必要な情報が保持されているため、DBとの通信がメインの仕事です。他にはバリデーションなんかもします。

エンティティはその通信結果の各レコードごとにインスタンスがあります。つまりエンティティはDBとは直接通信しません。

プログラム上での書き方も違います。テーブルは複数形であり、エンティティは単数形です。

関係としては、下のとおりです。

DB <-> Table <-> Entity <-> PHP

CakePHP3のORM\table::find()のイーガーロードとは

  • contain 関連をイーガーロード (eager load) するように定義します。

データの取り出しと結果セット

イーガーロードとは、N+1問題を回避する手段らしい。

 

まず、N+1問題とは?

ユーザーマスタと、著者のユーザIDを属性としてもつ記事テーブルがあるとします。

ブログのトップページに記事タイトルとユーザー名を並べて表示したいとき

SELECT 記事.タイトル, ユーザー.名前 FROM 記事, ユーザー
WHERE 記事.ユーザID = ユーザー.ユーザーID というSQL文が実行されそうですが、

実際は SELECT * FROM 記事 が最初に実行されます。

その後、その結果行(CakePHP3でいうとエンティティ)ごとに線形に 
SELECT * FROM ユーザー WHERE ユーザーID = 7 
SELECT * FROM ユーザー WHERE ユーザーID = 4
などとSQLが実行されます。

つまり、2つ以上のテーブルをSQLで関連付けているとき、最初に1クエリとその結果行のN行分のクエリが実行されてしまう問題です。

これを回避するために、N回あったユーザーテーブルへのSQLを一度にまとめます。
SELECT * FROM ユーザー WHERE ユーザーID = IN(7,4,0,1,40,21, ... , 90)

これがイーガーロードです。

Unable to find ~ panel. と出た

Templateディレクトリに間違った名前のディレクトリを作成してしまった。

具体的には単数形にしてしまっていた。

その後、PHPStormのリネーム機能でディレクトリ名を複数形にした。

すると、どのページにアクセスしてもUnable to find ~ panel.とエラーメッセージが出るようになった。

もう一度リネーム機能でもとに戻し、手動でディレクトリを修正すると正しく動作した。

CakePHP3のリバースルーティングとは

New router goodies » Debuggable - Node.js Consulting によると、

 

そもそもリンクの書き方は、文字列での指定と、連想配列での指定の2つがある。

①文字列の場合
$html->link('My post title', '/posts/view/5'
);

連想配列の場合
$html->link('My post title', array(
'controller' => 'posts',
'action' => 'view',
5 ));

後者の場合はリバースルーティングが有効になる。

すぐに localhost/posts/view/5 へのリンクを生成せず、routes.php内のRouter::connect()から、controllerとactionが同じものを探し、存在する場合はそのconnect()の第一引数に書き換える。

つまり、②が設定されていて
Router::connect('/hot_posts/*', array('controller' => 'posts', 'action' => 'view')); のように
コントローラとアクションが同じ配列を持つルートが有る場合は、
localhost/posts/view/5 ではなく、localhost/hot_posts/5に書き換える。

もう一つ例を挙げると、

テンプレート(.ctp)にこう書かれていて
$html->link('Top', array(
'controller' => 'Articles',
'action' => 'index' ));
routes.phpにこのように書かれているときは
$routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);

Topをクリックすると localhost/articles/indexではなく、localhost/にアクセスする。

echo $this->Form->create($article);の$articleが必要な理由

ブログチュートリアル - パート2

echo $this->Form->create($article); は、

echo $this->Form->create();としても動いているようにみえるけれど、

ArticlesControllerのsaveで例外(DB接続失敗、バリデーションエラー等)が起きた際、

$article = $this->Articles->patchEntity($article, $this->request->getData());がセットされる。

すなわち、書き込もうとしたものの、失敗したデータが渡される。

一般的なサイトを思い浮かべてもらうと分かるように、書き込みが失敗した際は
もう一度同じページが表示され、フォームは書き込み失敗したデータで初期化されている。

 

ブログチュートリアル1での文字化け

ブログチュートリアル

下記の方法で文字コードを指定してやる必要があります。

 

CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
) character set utf8;

 

もしくはphpmyadminにて、使用するDB画面から操作→照合順序でutf8mb4_unicode_ciを選択

PHPStormのfield accessed via magic methodについて

CakePHPでマジックメソッドを使う時に出る。
フィールド変数が無いから気をつけろということだそうだ。

PHPStormの設定で警告を抑制する方法と、アノテーションを書く方法がある。

www.thinkingmedia.ca

アノテーションだとこんな感じ。

use App\Model\Table\ArticlesTable; 
/**
* @property ArticlesTable Articles
*/
class ArticlesController extends AppController
{