具有属于两个更高模型的深度关联的保存模型

saving model with deep association belonging to both higher models

我有三个 table、ArticlesCommentsTags

Tags 属于 ArticlesComments

$this->Articles->patchEntity($entity, $this->request->getData(), [
    'associated' => ['Comments.Tags']
]);

出现以下错误:

SQLSTATE[HY000]: General error: 1364 Field 'article_id' doesn't have a default value 

Please try correcting the issue for the following table aliases:

    CommentsArticles

但是如果我只保存 'associated' => ['Comments'] 它可以保存 ArticleComments 加入 table 关联,只是不保存任何 Tags.

Articles table 有这些关联:

$this->hasMany('Tags', [
  'foreignKey' => 'article_id'
]);
$this->belongsToMany('Comments', [
  'foreignKey' => 'article_id',
  'targetForeignKey' => 'comment_id',
  'joinTable' => 'comments_articles'
]);

Comments table 有这些关联:

$this->hasMany('Tags', [
  'foreignKey' => 'comment_id'
]);
$this->belongsToMany('Articles', [
  'foreignKey' => 'comment_id',
  'targetForeignKey' => 'article_id',
  'joinTable' => 'comments_articles'
]);

Tags table有这些关联:

$this->belongsTo('Comments', [
  'foreignKey' => 'comment_id',
  'joinType' => 'INNER'
]);
$this->belongsTo('Articles', [
  'foreignKey' => 'article_id',
  'joinType' => 'INNER'
]);

这是修补后的实体,看起来像这样。

object(App\Model\Entity\Article) {

    'title' => 'example article name',
    'users' => [
        '_ids' => []
    ],
    'comments' => [
        (int) 0 => object(App\Model\Entity\Comment) {
            'id' => (int) 1,
            'content' => 'this is a comment',
            'tags' => [
                (int) 0 => object(App\Model\Entity\Tag) {

                    'name' => 'example tag name',
                    '[new]' => true,
                    '[accessible]' => [
                        'comment_id' => true,
                        'article_id' => true,
                        'comment' => true,
                        'article' => true
                    ],
                    '[dirty]' => [
                        'name' => true
                    ],
                    '[original]' => [],
                    '[virtual]' => [],
                    '[hasErrors]' => false,
                    '[errors]' => [],
                    '[invalid]' => [],
                    '[repository]' => 'Tags'

                }
            ],
            '[new]' => false,
            '[accessible]' => [
                'content' => true,
                'tags' => true,
                'articles' => true
            ],
            '[dirty]' => [
                'tags' => true
            ],
            '[original]' => [
                'tags' => [
                    (int) 0 => [
                        'name' => '0'
                    ]
                ]
            ],
            '[virtual]' => [],
            '[hasErrors]' => false,
            '[errors]' => [],
            '[invalid]' => [],
            '[repository]' => 'Comments'

        }
    ],
    '[new]' => true,
    '[accessible]' => [
        'title' => true,
        'tags' => true,
        'comments' => true,
        'users' => true
    ],
    '[dirty]' => [
        'title' => true,
        'users' => true,
        'comments' => true
    ],
    '[original]' => [
        'users' => []
    ],
    '[virtual]' => [],
    '[hasErrors]' => false,
    '[errors]' => [],
    '[invalid]' => [],
    '[repository]' => 'Articles'

}

CaekPHP 不支持,它只能在一个方向上填充直接关联/ 的外键。例如,您可以:

  • 预填充外键字段(当然只有当文章and/or评论已经存在时才有效)

  • 使用文章和评论记录的主键分别手动保存标签

  • 创建关联 类,在保存文章时将文章主键传递到选项中,并在保存标签时使用它来填充 article_id 字段

  • 挂钩 table 级别的保存过程以传递文章主键并用它填充标签

这是后一种解决方案的一个简单粗暴的示例,它还应该让您了解它如何在关联级别上工作:

ArticlesTable中:

public function beforeSave(
    \Cake\Event\Event $event,
    \Cake\Datasource\EntityInterface $entity,
    \ArrayObject $options
) {
    if (isset($options['Articles.id'])) {
        unset($options['Articles.id']);
    }
}

protected function _onSaveSuccess($entity, $options)
{
    if ($options['_primary']) {
        $options['Articles.id'] = $entity->get('id');
    }

    return parent::_onSaveSuccess($entity, $options);
}

TagsTable中:

public function beforeSave(
    \Cake\Event\Event $event,
    \Cake\Datasource\EntityInterface $entity,
    \ArrayObject $options
) {
    if (!$options['_primary'] &&
        isset($options['Articles.id'])
    ) {
        $entity->set('article_id', $options['Articles.id']);
    }
}