CakePHP3:bakeの落とし穴

とても便利なbakeですが、hasOneのリレーションを設定してくれないという特徴があります。

テーブルの例

例えば、次のようなテーブルがあるとします: usersテーブル

f:id:thebaker:20181021001722p:plain

user_profilesテーブル

f:id:thebaker:20181021000750p:plain

bakeした結果

Users hasMany UserProfilesというモデルが生成されます。

UsersTable.php

    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('users');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');

        $this->hasMany('UserProfiles', [
            'foreignKey' => 'user_id'
        ]);
    }

UserProfilesTable.php

    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setTable('user_profiles');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');

        $this->belongsTo('Users', [
            'foreignKey' => 'user_id',
            'joinType' => 'INNER'
        ]);
    }

なお、この挙動はuser_profiles.user_idカラムにユニークキーを貼っても変わりありません。

このままhasManyにしたまま進むとどうなるか?

bakeへの影響

コントローラやテンプレートをbakeした際に、hasMany前提でbakeされてしまいます。

その他の影響

フォームで関連するデータの保存を行う場合に、添字の指定が必要になります:

$this->Form->control('email');
$this->Form->control('user_profile.0.first_name'); // hasOneでbakeしていればuser_profile.first_nameと書ける
$this->Form->control('user_profile.0.last_name');

bake allは使わないほうが良さそう

bake allをすると、hasOneにしたいのにhasManyになり、hasMany前提でコントローラとテンプレートが生成されてしまいます。 よって、次のような手順が良さそうです:

  • まず、モデルをbakeして適宜hasManyをhasOneに修正する
  • コントローラ、テンプレートをbakeする

CakePHP3:アソシエーションされているデータをsaveの前に変更する

リクエストデータを変更する場合

$data = $this->request->getData();
$data['order_data']['name'] = "新しい名前";
$order = $this->Orders->patchEntity($order, $data);

エンティティのプロパティを変更する場合

$order->order_data->name = "新しい名前";
$order->dirty('order_data',true);
$this->Orders->save($order);

2行目のdirtyの指定を忘れると、保存されません

CakePHP3:コントローラで発行されたクエリをログする

debugkitを入れていればSQLは確認できますが、リダイレクト等が入っていて確認できない場合があります。 その対策です。

bootstrap.phpの変更

bootstrap.phpにこれを追加します:

Log::config('queries', [
    'className' => 'File',
    'path'      => LOGS,
    'file'      => 'queries.log',
    'scopes'    => ['queriesLog']
]);

【重用】デバッグモードの無効化

デバッグモードを無効にします(なぜこれをやらねばならないのか、理解に苦しみますが…)

ロギング用のコードの追加

コントローラで:

use Cake\Datasource\ConnectionManager;

を追加し、かつ、ログしたいクエリの周りに:

$connection = ConnectionManager::get('default');
$connection->logQueries(true);
 $this->Orders->save($order);
$connection->logQueries(false);

といった具合にlogQueriesを入れます。

Datasourcesについて

なお、app.phpのDatasourcesの中のlogfalseのままでOKです。

注意点

UPDATE前と後の値に変更がない場合、UPDATEは発行されないようです(したがってログにも出ない)

Git:ブランチを削除する

ローカルの場合

ローカルブランチ一覧を表示

git branch

マージ済みのローカルブランチを削除

git branch -d ブランチ名

マージ済みか否かを問わないで、ローカルブランチを削除

git branch -D ブランチ名

リモートの場合

リモートブランチ一覧を表示

git branch --remote

リモートブランチの削除

git push origin --delete ブランチ名