【问题标题】:Setting a default value on join table from another table when model is edited or created编辑或创建模型时从另一个表连接表设置默认值
【发布时间】:2020-02-02 16:27:29
【问题描述】:

希望有人能指出我正确的方向。

我有一个应用程序,其中包括(除其他外)建议和评估。它们与一个包含额外字段的连接表连接在一起,我想更新这些字段,但我正在努力弄清楚如何更新。

正如您在上面看到的,当我创建推荐时,我设置了以下字段:

  • default_user_impact
  • default_business_impact
  • default_deployment_complexity
  • default_criticality

现在,当我创建一个新的评估或编辑一个没有链接任何建议的评估时,评估保存得很好,因为不需要将任何内容写入连接表。

当我尝试编辑评估以包含一个或多个建议时,应用程序尝试将链接写入连接表并失败,因为未指定 user_impact、business_impact、deployment_complexity 和 criticality 字段 - 完全正常,因为我有在 MySQL 中将字段设置为必需的吗?我在 CakePHP 中遇到的错误是

SQLSTATE[HY000]:一般错误:1364 字段 'user_impact' 没有默认值

我希望能够在编辑或创建评估时使用建议表中的值来填充相应的连接表条目。有什么想法可以解决这个问题吗?

举个例子:

  • user_impact = default_user_impact
  • business_impact = default_business_impact
  • deployment_complexity = default_deployment_complexity
  • criticality = default_criticality

我想这样做的原因是,我可以使用这些字段的值设置建议,然后如果用户想要运行评估并且他们只想为自己的评估调整值,那么它就赢了'不影响他人等。

这是我的 AssessmentsTable 关联。

    $this->belongsToMany('Recommendations', [
        'foreignKey' => 'assessment_id',
        'targetForeignKey' => 'recommendation_id',
        'joinTable' => 'assessments_recommendations',
        'through' => 'assessments_recommendations',
    ]);

这是我的 RecommendationsTable 关联。

    $this->belongsToMany('Assessments', [
        'foreignKey' => 'recommendation_id',
        'targetForeignKey' => 'assessment_id',
        'joinTable' => 'assessments_recommendations',
        'through' => 'assessments_recommendations',
    ]);

这是我的 AssessmentsRecommendations 协会:

    $this->belongsTo('Assessments', [
        'foreignKey' => 'assessment_id',
        'joinType' => 'INNER',
    ]);
    $this->belongsTo('Recommendations', [
        'foreignKey' => 'recommendation_id',
        'joinType' => 'INNER',
    ]);

这是我的 AssessmentsController 编辑功能的样子:

public function edit($id = null)
{
    $assessment = $this->Assessments->get($id, [
        'contain' => ['Recommendations'],
    ]);

    if ($this->request->is(['patch', 'post', 'put'])) {
        $assessment = $this->Assessments->patchEntity($assessment, $this->request->getData(), ['associated'=>['Recommendations._joinData']]);            
        if ($this->Assessments->save($assessment, ['associated' => ['Recommendations._joinData']])) {
            $this->Flash->success(__('The assessment has been saved.'));       

            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('The assessment could not be saved. Please, try again.'));
    }
    $clients = $this->Assessments->Clients->find('list', ['limit' => 200]);
    $recommendations = $this->Assessments->Recommendations->find('list', ['limit' => 200]);
    $this->set(compact('assessment', 'clients', 'recommendations'));
}

现在,当我将 beforeSave 函数添加到 AssessmentsRecommendationsTable 时,我看到以下错误:

传递给 App\Model\Table\AssessmentsRecommendationsTable::beforeSave() 的参数 2 必须是 App\Model\Table\EntityInterface 的实例,给定的 Cake\ORM\Entity 的实例,在 /var/www/html/ 中调用csa-portal/vendor/cakephp/cakephp/src/Event/EventManager.php 在第 310 行

任何帮助将不胜感激。

【问题讨论】:

  • 你用的是哪个 cakephp 版本?
  • 我使用的是 CakePHP 4.0.3。

标签: mysql cakephp cakephp-3.0


【解决方案1】:

首先,您使用的关联是错误的。应该是这样的

用于评估表

   $this->hasMany('AssessmentsRecommendations', [
        'foreignKey' => 'assessment_id'
   ]);

推荐表

   $this->hasMany('AssessmentsRecommendations', [
        'foreignKey' => 'recommendation_id'
   ]);

对于评估建议表

    $this->belongsTo('Assessments', [
        'foreignKey' => 'assessment_id',
        'joinType' => 'INNER',
    ]);

    $this->belongsTo('Recommendations', [
        'foreignKey' => 'recommendation_id',
        'joinType' => 'INNER',
    ]);

现在对于默认值,您必须在 AssessmentsRecommendationsTable.php 文件中使用用户 beforeSave。您可以在保存前根据需要在此处修改数据。

public function beforeSave(Event $event, EntityInterface $entity, \ArrayObject $options)
    {
        if ($entity->isNew()) { // Returns true when you add new record
            $recommendation = TableRegistry::getTableLocator()->get('Recommendations')->get($entity->recommendation_id);
            $entity->user_impact = $recommendation->default_user_impact;
            $entity->business_impact = $recommendation->default_business_impact;
            $entity->deployment_complexity = $recommendation->default_deployment_complexity;
            $entity->criticality = $recommendation->default_criticality;
        }
    }
  • 我从未使用过 belongsToMany,如果关联对您有用,则忽略关联部分。

【讨论】:

  • 感谢这个阿曼。我正在测试您的 beforeSave 事件,因为这对我来说似乎是合乎逻辑的。我在保存评估时收到此错误。顺便说一句,我保留了我的联想,因为它们似乎运作良好。希望这不是问题。 传递给 App\Model\Table\AssessmentsRecommendationsTable::beforeSave() 的参数 2 必须是 App\Model\Table\EntityInterface 的实例,给定的 Cake\ORM\Entity 的实例,在 /var/www/html/ 中调用csa-portal/vendor/cakephp/cakephp/src/Event/EventManager.php 在第 310 行 我在原始帖子中添加了我的 AssessmentsController 编辑功能。
  • 我已将详细信息添加到原始帖子中。
  • 您可以尝试像 beforeSave(Event $event, $entity, \ArrayObject $options) 那样从 beforeSave 中删除 EntityInterface。根据文档book.cakephp.org/4/en/orm/table-objects.html#beforesave,它应该是 EntityInterface
  • 太棒了!谢谢!这有效 - 现在做一些测试。将其标记为答案。
【解决方案2】:

您是否考虑过编写规则来处理这个问题?

https://book.cakephp.org/3/en/orm/validation.html#applying-application-rules

【讨论】:

  • 感谢您的链接。我读过那篇文章,最初的想法是规则,但我完全不知道如何针对 joinData 实施规则。
  • 由于规则可以是可调用的,因此您可以拥有完成任务所需的尽可能多的逻辑。当您检测到可能导致问题的列更改时,您的规则可以执行它需要的任何过程,以确保所有数据正确对齐。在继续保存之前,您可能需要直接读取加入记录以检查它?
  • 如果我正确地解决了您的问题,您的规则将适用于评估的创建或编辑,如果连接的联接不存在或具有错误的值,您将从建议中读取值并设置它们以进行保存。
  • 该规则适用于评估的创建或编辑。但是,如果我编辑评估并说也许我添加了额外的建议,我不想再次更新该评估的所有值,只更新新添加的建议。
  • 在实体上使用dirtygetOriginal 方法,您可以使您的规则足够具体,以仅针对新添加的建议。 book.cakephp.org/3/en/orm/…
猜你喜欢
  • 1970-01-01
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 2016-07-05
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多