сохраняющая модель с глубокой ассоциацией, принадлежащая обеим старшим моделям - PullRequest
0 голосов
/ 26 апреля 2019

У меня есть три таблицы: Articles, Comments и Tags.

Tags принадлежат как Articles, так и Comments.

$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(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'

}

1 Ответ

1 голос
/ 26 апреля 2019

CaekPHP не поддерживает это, он может заполнять только внешние ключи прямых ассоциаций / в одном направлении. Вы могли бы например:

  • предварительно заполнить поля внешнего ключа (которые, конечно, будут работать только тогда, когда статья и / или комментарий уже существуют)

  • вручную сохранить теги отдельно, используя первичные ключи статьи и записи комментариев

  • создает классы ассоциаций, которые передают первичный ключ статьи в параметры при сохранении статьи, и используют его для заполнения поля article_id при сохранении тега

  • подключиться к процессу сохранения на уровне таблицы, чтобы передать первичный ключ товара и заполнить его тегами

Вот быстрый и грязный пример последнего решения, который также должен дать вам представление о том, как оно может работать на уровне ассоциации:

В 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']);
    }
}
...