首页 > 解决方案 > CakePHP:无法通过 belongsTo 关联子项将数据保存到父实体

问题描述

问题描述

我正在尝试配置 CakePHP 3.7 API 以儿童优先的方式保存关联数据。实体——为了举例,我们称它们为UsersPersons——它们的关系如下:

用户表.php

...
  $this->belongsTo('Persons', [
    'foreignKey' => 'person_id',
    'joinType' => 'LEFT',
    'className' => 'MyPlugin.Persons',
  ]);
...

PersonsTable.php

  $this->hasOne('Users', [
    'foreignKey' => 'person_id',
    'className' => 'MyPlugin.Users'
  ]);

在各自的实体中,它们各自将彼此的属性可见性设置为true。我想要做的是POST路由/users/UsersController.php)并让它也保存Persons包含的对象。有效载荷是这样的:

{
    "username": "foo",
    "password": "bar",
    "persons": {
        "dob": "1982-07-03",
    }
}

保存方法的相关部分如下,来自UsersController.php

  if ($this->request->is('post') && !empty($this->request->getData())) {
    $data = $this->request->getData();
    $newEntity = $this->Users->newEntity($data, ['associated' => 'Persons']);

    $savedEntity =  $this->Users->save($newEntity);
  ...

错误

这会产生以下 SQL 错误。

PDOException:SQLSTATE [23502]:非空违规:7 错误:“person_id”列中的空值违反非空约束细节:失败行包含(1、null、foo、bar)

我知道这是因为 Cake 试图保存到Users而不必person_id满足外键约束。在我的应用程序域中,无法反转这种 FK 关系,因为我们需要向左的一对多关系(用户 -> 1 个人)。

id我怀疑在有效负载的persons对象中发送一个JSON将允许它正确保存。但是,由于各种原因,这在运行时是不可能的。例如,这就是它在“保存数据”CakePHP Book 页面中的显示方式......

$data = [
  'title' => 'First Post',
  'user' => [
      'id' => 1,
      'username' => 'mark'
  ]
];

...
$article = $articles->newEntity($data, [
    'associated' => ['Users']
]);

$articles->save($article);

我知道以下内容也可能按照xPfqHZ对类似问题的建议工作,Persons可以保存到Users,但与我正在尝试做的事情相比,它感觉不太合适,并且感觉好像有一种方法可以通过Users.

  if ($this->request->is('post') && !empty($this->request->getData())) {
    $data = $this->request->getData();
    $newEntity = $this->Users->Persons->newEntity($data, ['associated' => 'Persons']);

    $savedEntity =  $this->Users->Persons->save($newEntity);
  ...

工作

现在我相信这在 CakePHP 2.X 中曾经是可能的,正如ndm在一个类似问题上的回答中所说的那样,一个人试图通过实体在一个请求中保存belongsTo关联实体及其父实体。hasOnebelongsTo

这是预期的行为,saveAssociated() 并不是只保存关联记录,它也会保存主记录,所以你应该只使用 saveAssociated(),不需要手动设置外键等,CakePHP 会做那是自动的。

控制器

public function create() {
    if ($this->request->is('post') && !empty($this->request->data)):
        $this->CandidatesProblemReport->create();
        if ($this->CandidatesProblemReport->saveAssociated($this->request->data)):
            // ...
        endif;
    endif;
}

但是,在文档中,我无法在实体继承的对象上找到或使用该saveAssociated()方法。调用它会产生方法未找到错误。此方法似乎只存在于文档中详述的对象上。除非我遗漏了明显的东西,否则有没有办法使用它,或者它是否被它的兄弟方法在内部使用?Cake\ORM\TableUsersCake\ORM\AssociationBelongsTo()

记录/倾倒实体

使用Cake\Log\Log::error($newEntity);die(var_dump($newEntity));显示Users水合到对象中的有效负载数据,但我没有看到Persons附加的对象(见下文)。

object(MyPlugin\Model\Entity\User)[299]
  public 'username' => string 'foo' (length=3)
  public 'password' => string 'bar' (length=3)
  public '[new]' => boolean true
  public '[accessible]' => 
    array (size=5)
      '*' => boolean false
      'person_id' => boolean true
      'username' => boolean true
      'password' => boolean true
      'person' => boolean true
  public '[dirty]' => 
    array (size=2)
      'username' => boolean true
      'password' => boolean true
  public '[original]' => 
    array (size=0)
      empty
  public '[virtual]' => 
    array (size=0)
      empty
  public '[hasErrors]' => boolean false
  public '[errors]' => 
    array (size=0)
      empty
  public '[invalid]' => 
    array (size=0)
      empty
  public '[repository]' => string 'MyPlugin.Users' (length=17) 

试图\Cake\Log\Log::error($savedEntity);在日志文件中不显示任何内容。

save()关联论点

我考虑的另一个解决方案是使用文档中所示的$options['associated]of (摘录如下)。如下设置为true,错误仍然发生。save()

保存(Cake\Datasource\EntityInterface $entity,数组 $options [])

... associated:如果为 true,则只要为关联定义的属性标记为脏,它将保存在传递的 $entity 中找到的第一级关联实体。如果是数组,它将被解释为要保存的关联列表。通过将自定义选项设置为数组值,可以使用此键提供不同的选项来保存关联的表对象。如果为 false,则不会保存任何关联的记录。(默认:真)...

UsersController.php

  if ($this->request->is('post') && !empty($this->request->getData())) {
    $data = $this->request->getData();
    $newEntity = $this->Users->newEntity($data, ['associated' => 'Persons']);

    $savedEntity =  $this->Users->save($newEntity, ['associated' => true]);
  ...

概括

如果不经历PersonsController.php和利用它的关系,hasOne我很难通过.UsersPersonsUsersController.php

如果我错过了任何重要信息,或者您有问题/需要更多信息,请询问!我可能错过了一些明显的东西,但我会很感激任何可能的建议/解决方案。

标签: phpcakephpassociationscakephp-3.0cakephp-2.0

解决方案


正如@ndm 所指出的,错误在于发布的数据。根据文档的“保存数据:保存属于关联”页面:

保存 belongsTo 关联时,ORM 需要一个嵌套实体,该实体以单数下划线版本的关联名称命名。

张贴的密钥persons应该是person. 同样,如果实体命名为PersonSnapshots,则水合到实体中的有效负载中的相关键必须是person_snapshot


推荐阅读