Описание проблемы
Я пытаюсь настроить CakePHP 3.7 API для сохранения связанных данных в дочернем порядке.Сущности - например, давайте назовем их Users
и Persons
- и их отношения будут следующими:
UsersTable.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]: нарушение не равняется NULL: 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
и ее родительскую сущность hasOne
в одном запросе через сущность belongsTo
.
Это ожидаемое поведение, 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\Table
, который Users
сущность наследуется от, в документации.Вызов этого метода приводит к ошибке «not found».Этот метод существует только для объекта Cake\ORM\Association
, как описано в документации .Если я не пропускаю очевидное, есть ли способ использовать это или он используется внутри BelongsTo()
и его родственными методами?
Запись / сброс сущности
Использование 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]
из save()
, как показано в документации (выдержка ниже).Если для этого параметра установлено значение true, как показано ниже, ошибка все еще возникает.
save (Cake \ Datasource \ EntityInterface $ entity, array $ options [])
... ассоциирован : если true, то будет сохранен ассоциированный 1-й уровеньсущности, поскольку они находятся в переданном $ entity, когда свойство, определенное для ассоциации, помечено как грязное.Если массив, он будет интерпретирован как список ассоциаций, которые будут сохранены.Можно использовать различные параметры для сохранения в связанных табличных объектах, используя этот ключ, задав пользовательским параметрам значение массива.Если ложь, никакие связанные записи не будут сохранены.(по умолчанию: true) ...
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
, мне не очень повезло получить мои Users
и Persons
данные для сохранения через UsersController.php
.
Если я пропустил какую-либо важную информацию, или у вас есть вопросы / вам нужно больше вопросов, пожалуйста, задавайте! Возможно, я упустил что-то очевидное, но я был бы признателен за любые возможные предложения / решения.