cakephp3

CakePHP3のハマリどころ:孫associationを指定する記法はメソッドによって異なる

More than 1 year has passed since last update.

Cakephp3を使っていると頻出するassociation指定について、特に孫associationを指定する場合の記法が意外と難しいのでまとめました。

パターン1. クエリビルダのcontain

CakePHP3をやっていると一番馴染み深いパターンではないでしょうか。
ただ、この書き方だけ知っていると、他ではまることも・・・。

'contain' => [
  'Childs' => [
    'GrandChilds',
    'OtherGrandChilds'
  ]
  ...
]

パターン2. Entity->newEntity() など

こちらが比較的はまりがちのパターンで、パターン1と同じように書いてしまうと、
孫アソシエーションがうまく働いてくれません。
特にエラーメッセージなども出ないので、孫エンティティの一括登録を諦めてしまう人もいるのではないでしょうか(私です)

該当するメソッドはこちらになります。(他にもありましたらコメントお願いします)
- Entity->newEntity() , patchEntity() , save()
- FormHelper->create() のcontext=>validatorオプション

記法としては2種類存在します。

.繋ぎで深い関連を指定するパターン

Users->newEntity($data, [
        'associated' => [
            'Childs' => [
                'validate' => 'register'
            ],
            'Childs.GrandChilds' => [
                'validate' => 'register'
            ],
            'Childs.OtherGrandChilds' => [
               'validate' => 'register'
            ],
        ], 
    ]);

ポイントとしては、

  • 配列のネストではなく、.繋ぎで、より深い関連を指定する
  • テーブル名のネスト配列にはvalidateを指定する(省略された場合には defaultValidator が呼び出されます)

FormHelper->create() のcontext=>validatorで書く場合はこんな感じになります。

$this->Form->create($user,[
                    'type' => 'post',
                    'url' => [
                        'action' => 'save',
                        'controller' => 'user',
                    ],
                    'context' => [
                        'validator' => [
                            'Childs' => 'default',
                            'Childs.GrandChilds' => 'order',
                            'Childs.OtherGrandChilds' => 'order'
                        ]
                    ],
                ])

associated オプションを入れ子で使用する

こちらは公式のデータの保存に書かれている方法です。

// 入れ子になったアソシエーション付きの新しいエンティティ
$articles->newEntity($data, [
    'associated' => [
        'Tags', 
        'Comments' => [
            'associated' => ['Users']
        ]
    ]
]);

子エンティティの配列の中に、さらにassociatedオプションを指定する感じですね。
(試してないのですが、こちらの記法でFormHelper->create()はどう書くのでしょう・・・。validatorのなかにassociatedを書くのでしょうか。


いかがでしょうか。個人的には .区切りの記法のほうがネストが複雑にならず、シンプルに書けるイメージです。