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



我有三个表,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']保存它就可以保存Article并使用连接表关联Comments,只是不保存任何Tags.

Articles表具有以下关联:

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

Comments表具有以下关联:

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

Tags表具有以下关联:

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

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

object(AppModelEntityArticle) {
    'title' => 'example article name',
    'users' => [
        '_ids' => []
    ],
    'comments' => [
        (int) 0 => object(AppModelEntityComment) {
            'id' => (int) 1,
            'content' => 'this is a comment',
            'tags' => [
                (int) 0 => object(AppModelEntityTag) {
                    '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 不支持,它只能在一个方向上填充直接关联的外键。例如,您可以:

  • 预填充外键字段(当然,只有在文章和/或注释已经存在时才有效(

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

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

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

下面是后一种解决方案的快速而肮脏的示例,它还应该让您了解它如何在关联级别工作:

ArticlesTable

public function beforeSave(
    CakeEventEvent $event,
    CakeDatasourceEntityInterface $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(
    CakeEventEvent $event,
    CakeDatasourceEntityInterface $entity,
    ArrayObject $options
) {
    if (!$options['_primary'] &&
        isset($options['Articles.id'])
    ) {
        $entity->set('article_id', $options['Articles.id']);
    }
}

最新更新