возможная ошибка в рамках CakePHP, но не уверен в этом
database.users
+-----+---------------+----------+
| id | user_group_id | username |
+-----+---------------+----------+
| INT | INT | VARCHAR |
database.user_settings
+-----+---------------+----------+
| id | user_id | data |
+-----+---------------+----------+
| INT | INT | VARCHAR |
$this->table('users');
$this->displayField('id');
$this->primaryKey('id');
$this->belongsTo('UserGroups', [
'foreignKey' => 'user_group_id'
]);
$this->hasOne('UserSettings', [
'foreignKey' => 'user_id'
]);
$this->table('user_settings');
$this->displayField('id');
$this->primaryKey('id');
$this->belongsTo('Users', [
'foreignKey' => 'user_id'
]);
// And folowing validation rules:
$validator
->add('id', 'valid', ['rule' => 'numeric'])
->allowEmpty('id', 'create')
// UserSettings.user_id validation rule:
->add('user_id', 'valid', ['rule' => 'numeric'])
->requirePresence('user_id', 'create')
->notEmpty('user_id');
$user = $this->Users->newEntity();
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->data, [
'associated' => ['Users.UserSettings']
]);
// Tried it also this way, won't change anything
//$user = $this->Users->patchEntity($user, $this->request->data, [
// 'associated' => ['user_setting']
//]);
$this->Users->save($user,['associated' => ['UserSettings']]);
}
Пример входных данных ($ this-> request-> data):
[
'user_group_id' => 1, // Not related to question
'username' => 'test', // This will be saved without core modifications
'user_setting' => [
'data' => 'sample data' // Saved only after "fix" described below
]
];
Это сохранит родительскую таблицу (пользователи), но не дочернюю таблицу (user_settings).
Если я положу это изменение в ORM\Associations\HasOne::saveAssociated(...)
// $this->property() == 'user_setting'
if (is_array($targetEntity)) {
$targetEntity = $this->target()->newEntity($targetEntity);
}
Это мгновенно сработает так, как я хотел. HasOne на самом деле имеет требуемые данные, но также проверяет, находятся ли данные внутри Entity, в этом случае они были в массиве.
Я играл с разными комбинациями названий ассоциаций, и кажется, что так и должно быть.
Можно ли как-то убедиться, что данные будут преобразованы в объект Entity?
Я думаю, что это должно сработать, поскольку есть все необходимые данные и, похоже, они правильно обрабатывают отношения.
С помощью @ndm мне удалось решить эту проблему с помощью специального маршаллера.
Сначала я взглянул на отдельные валидаторы, но для меня это кажется слишком сложным и хрупким способом решения очень простой прямой задачи.
Мое честное мнение состоит в том, что все это должно как-то решаться внутри ядра фреймворка.
Таким образом, вы должны быть уверены, что «пользовательская проверка» будет использоваться только тогда, когда UserSettings будет создан через Users, а user_settings.user_id должен быть легко доступен.
class UsersMarshaller extends Marshaller {
protected function _validate($data, $options, $isNew) {
$errors = parent::_validate($data, $options, $isNew);
if ($isNew) {
unset($errors['user_setting']['user_id']['_required']);
}
return $errors;
}
}
И в UsersTable
учебный класс:
public function marshaller() {
return new UsersMarshaller($this);
}
patchEntity(...)
параметры вызова были ошибочными, даже если эти параметры делали что-то, что делало их похожими на правильные.
Ассоциации должны быть такими: ['associated' => ['UserSettings']]
, Не Users.UserSettings
или же user_setting
,
Правильное значение для associated
собственность будет UserSettings
что вы использовали, Users.UserSettings
был бы Users > Users > UserSettings
ассоциация.