CakePHP3 beforeSaveでassociatedを書き換える時の注意点

標準

TL;DR: beforeSaveでassociatedを書き換えるときは、ドット記法は使えないので配列で指定する。


Authors hasMany Posts hasMany Comments のリレーションがあるとする。

Authorsから、Posts、Commentsをまとめてsaveしたい場合、通常のsaveであればassociatedに指定してやればよい。

$this->Authors->save($author, [
    'associated' => ['Posts.Comments'],
]);

通常はこれでよいとして、特殊な要件により通常はPostsまでの保存で、あるときだけCommentsも保存すると言った場合、Model.beforeSaveイベントにフックしてassociatedを書き換えることを検討する。

単純に以下のコードでは動かない。

// Listenerクラスで
public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)
{
    $table = $event->getSubject();
    if ($table instanceof AuthorsTable) {
        $options['associated'][] = 'Posts.Comments';
    }
    return true;
}

上記だと InvalidArgumentException : Cannot save Posts.Comments, it is not associated to Authors と怒られる。

なぜならば associated オプションはbeforeSaveに入る前に正規化されているため、ドット記法ではなく以下のように配列化しておく必要がある。

public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)
{
    $table = $event->getSubject();
    if ($table instanceof AuthorsTable) {
        $options['associated']['Posts'][] = 'Comments';
    }
    return true;
}

コメントを残す

Page optimized by WP Minify WordPress Plugin