i am developing a REST api with cakephp 3 and i found a strange behaviour.
I changed the routes.config so .json, .xml requests are possible. I also loaded the RequestHandler component in the controllers initialize method.
My register action in UsersController()
public function register()
{
$message = array('code' => '200', 'message' => 'The user could not be saved. Please, try again.');
$user = $this->Users->newEntity($this->request->data);
if ($this->request->is('post')) {
if ($this->Users->save($user)) {
$message = array('code' => '100', 'message' => 'The user has been registred');
}
}
$this->set([
'message' => $message,
'user' => $user,
'_serialize' => ['message', 'user']
]);
}
Model validation:
public function validationDefault(Validator $validator)
{
$validator
->add('id', 'valid', ['rule' => 'numeric'])
->allowEmpty('id', 'create');
$validator
->requirePresence('username', 'create');
$validator
->notEmpty('username', 'A username is required')
->add('username', [
'length' => [
'rule' => ['minLength', 3],
'message' => 'Username need to be at least 3 characters long',
]
])
->notEmpty('password', 'A password is required')
->add('password', [
'length' => [
'rule' => ['minLength', 3],
'message' => 'Password need to be at least 3 characters long',
]
]);
return $validator;
}
The problem:
If i make a post request with content header application/x-www-form-urlencoded all works fine, a new user is saved and the validation rules is taken into account. But if i make a post request with for example content header application/json a empty user is saved. The reason is $this->request->data is null. But why cakephp saves the empty user? (in the database username and password is declared as not null)
null will not trigger validationThe first argument for newEntity() is optional, so when passing null, it's like you haven't passed anything at all, resulting in a fresh, new, empty entity being created, that is not going to be validated.
That's one of the reasons why you shouldn't do what you are doing there, you should not pass request data to newEntity(), but use patchEntity() on the entity created with newEntity() instead, just like it's being done in the code generated by the bake shell.
// ...
$user = $this->Users->newEntity();
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->data);
if ($this->Users->save($user)) {
// ...
}
}
// ...
That way passing null will not be accepted, and cause an error instead, as the argument is required, and must be an array.
I guess the docs need to be updated to reflect that.
Additionally to validating data when creating/updating entities, there are also application/table rules, which are going to be applied in any case before saving the data. Using these rules you can prevent such problematic save operations no matter how the entity was created.
Here's a very basic example that tests a field for being "empty":
public function buildRules(RulesChecker $rules)
{
$rules->add(function ($entity, $options) {
return !empty($entity->get('field'));
});
return $rules;
}
See also Bookbook > ORM > Saving Data > Applying Application Rules
null from being used at allIn case null is an expected value, ie it's valid that it happens to be null under certain circumstances, then you might even want to add proper precautions and test the data for being null before trying to work with it.
NOT NULL?Well, that's fairly easy to explain, the INSERT query generated by the ORM will contain only the fields of the entity that are dirty (changed), and by default that are only the fields automatically updated by the Timestamp behavior, so that an insert of an empty entity may result in something like
INSERT INTO table (created, modified) VALUES ('2015-05-06 11:34:49', '2015-05-06 11:34:49')
Depending on your DBMS and configuration this will not yield any error, MySQL for example will set the non passed columns to their implicit default values when not running in strict mode, so you'd only receive an error in case the actual value NULL would be passed for a specific NOT NULL column.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With