Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cakephp 3 saves entity although request-data is null

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)

like image 249
q0re Avatar asked Aug 15 '26 13:08

q0re


1 Answers

Passing null will not trigger validation

The 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.

Use additional application/table rules

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

Prevent null from being used at all

In 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.

Why is the record inserted though the columns say 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.

like image 156
ndm Avatar answered Aug 18 '26 04:08

ndm



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!